perp-cli 0.12.17 → 0.14.1

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.md +247 -27
  2. package/dist/_stderr-filter.js +0 -1
  3. package/dist/agent-wallet/lighter-keystore.d.ts +11 -0
  4. package/dist/agent-wallet/lighter-keystore.js +92 -10
  5. package/dist/agent-wallet/passphrase.d.ts +1 -1
  6. package/dist/agent-wallet/passphrase.js +16 -3
  7. package/dist/agent-wallet/store.d.ts +37 -4
  8. package/dist/agent-wallet/store.js +132 -0
  9. package/dist/agent-wallet/venue-keystore.d.ts +14 -0
  10. package/dist/agent-wallet/venue-keystore.js +121 -0
  11. package/dist/api/public/hyperliquid.js +4 -4
  12. package/dist/api/public/lighter.js +5 -5
  13. package/dist/api/public/pacifica.d.ts +0 -1
  14. package/dist/api/public/pacifica.js +4 -13
  15. package/dist/api/public/urls.d.ts +9 -1
  16. package/dist/api/public/urls.js +35 -13
  17. package/dist/arb/file-lock.d.ts +11 -0
  18. package/dist/arb/file-lock.js +74 -0
  19. package/dist/arb/index.d.ts +2 -2
  20. package/dist/arb/index.js +2 -2
  21. package/dist/arb/pending-entry.d.ts +32 -0
  22. package/dist/arb/pending-entry.js +77 -0
  23. package/dist/arb/sizing.d.ts +6 -13
  24. package/dist/arb/sizing.js +12 -51
  25. package/dist/arb/state.d.ts +45 -12
  26. package/dist/arb/state.js +214 -42
  27. package/dist/arb/utils.d.ts +20 -6
  28. package/dist/arb/utils.js +43 -39
  29. package/dist/bot/conditions.d.ts +4 -4
  30. package/dist/bot/conditions.js +11 -6
  31. package/dist/bot/config.d.ts +17 -1
  32. package/dist/bot/config.js +48 -12
  33. package/dist/bot/engine.d.ts +61 -2
  34. package/dist/bot/engine.js +610 -144
  35. package/dist/bot/fill-size.d.ts +7 -0
  36. package/dist/bot/fill-size.js +18 -0
  37. package/dist/bot/index.d.ts +1 -1
  38. package/dist/bot/index.js +1 -1
  39. package/dist/bot/perp-order.d.ts +99 -0
  40. package/dist/bot/perp-order.js +299 -0
  41. package/dist/bot/presets.d.ts +7 -0
  42. package/dist/bot/presets.js +17 -0
  43. package/dist/bot/quarantine.d.ts +75 -0
  44. package/dist/bot/quarantine.js +190 -0
  45. package/dist/bot/quote-rules.d.ts +23 -0
  46. package/dist/bot/quote-rules.js +69 -0
  47. package/dist/bot/strategies/avellaneda-mm.d.ts +32 -2
  48. package/dist/bot/strategies/avellaneda-mm.js +72 -70
  49. package/dist/bot/strategies/basis-arb.js +2 -0
  50. package/dist/bot/strategies/dca-strategy.d.ts +2 -0
  51. package/dist/bot/strategies/dca-strategy.js +5 -0
  52. package/dist/bot/strategies/funding-arb-strategy.d.ts +43 -3
  53. package/dist/bot/strategies/funding-arb-strategy.js +571 -380
  54. package/dist/bot/strategies/funding-arb-utils.d.ts +48 -23
  55. package/dist/bot/strategies/funding-arb-utils.js +159 -195
  56. package/dist/bot/strategies/funding-arb-v2.d.ts +32 -0
  57. package/dist/bot/strategies/funding-arb-v2.js +258 -47
  58. package/dist/bot/strategies/funding-auto.js +215 -194
  59. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +14 -0
  60. package/dist/bot/strategies/spot-perp-arb-strategy.js +217 -50
  61. package/dist/bot/strategies/spot-perp-executor.d.ts +73 -19
  62. package/dist/bot/strategies/spot-perp-executor.js +319 -120
  63. package/dist/bot/strategies/spot-perp-state.d.ts +43 -0
  64. package/dist/bot/strategies/spot-perp-state.js +70 -0
  65. package/dist/bot/strategy-types.d.ts +6 -0
  66. package/dist/bot/tui/BotDashboard.d.ts +7 -2
  67. package/dist/bot/tui/BotDashboard.js +6 -3
  68. package/dist/bridge-engine.d.ts +120 -19
  69. package/dist/bridge-engine.js +710 -422
  70. package/dist/bridge-signers.d.ts +54 -0
  71. package/dist/bridge-signers.js +161 -0
  72. package/dist/cache.d.ts +4 -1
  73. package/dist/cache.js +11 -0
  74. package/dist/cli-flags.d.ts +50 -0
  75. package/dist/cli-flags.js +104 -0
  76. package/dist/cli-program.d.ts +35 -0
  77. package/dist/cli-program.js +303 -0
  78. package/dist/cli-spec.js +1 -1
  79. package/dist/client-id-tracker.js +11 -2
  80. package/dist/commands/account.d.ts +7 -1
  81. package/dist/commands/account.js +70 -92
  82. package/dist/commands/agent-import.d.ts +114 -0
  83. package/dist/commands/agent-import.js +794 -0
  84. package/dist/commands/agent.d.ts +232 -2
  85. package/dist/commands/agent.js +1858 -955
  86. package/dist/commands/alerts.d.ts +1 -0
  87. package/dist/commands/alerts.js +31 -28
  88. package/dist/commands/arb/index.d.ts +60 -1
  89. package/dist/commands/arb/index.js +381 -384
  90. package/dist/commands/arb-auto.d.ts +132 -4
  91. package/dist/commands/arb-auto.js +1474 -967
  92. package/dist/commands/arb.d.ts +3 -1
  93. package/dist/commands/arb.js +62 -30
  94. package/dist/commands/bot.js +127 -47
  95. package/dist/commands/bridge.d.ts +2 -1
  96. package/dist/commands/bridge.js +339 -192
  97. package/dist/commands/builder.d.ts +55 -0
  98. package/dist/commands/builder.js +387 -0
  99. package/dist/commands/funds-onchain.d.ts +32 -0
  100. package/dist/commands/funds-onchain.js +248 -0
  101. package/dist/commands/funds.d.ts +25 -0
  102. package/dist/commands/funds.js +925 -245
  103. package/dist/commands/history.js +102 -54
  104. package/dist/commands/init.d.ts +107 -15
  105. package/dist/commands/init.js +1116 -249
  106. package/dist/commands/jobs.d.ts +2 -1
  107. package/dist/commands/jobs.js +77 -15
  108. package/dist/commands/manage.js +136 -91
  109. package/dist/commands/market.d.ts +4 -1
  110. package/dist/commands/market.js +35 -32
  111. package/dist/commands/outcome.d.ts +10 -0
  112. package/dist/commands/outcome.js +396 -0
  113. package/dist/commands/plan.js +52 -12
  114. package/dist/commands/portfolio.d.ts +1 -0
  115. package/dist/commands/portfolio.js +60 -72
  116. package/dist/commands/rebalance.d.ts +2 -1
  117. package/dist/commands/rebalance.js +33 -43
  118. package/dist/commands/risk.js +46 -19
  119. package/dist/commands/settings.d.ts +1 -0
  120. package/dist/commands/settings.js +246 -51
  121. package/dist/commands/trade.d.ts +50 -0
  122. package/dist/commands/trade.js +1943 -695
  123. package/dist/commands/wallet.d.ts +30 -1
  124. package/dist/commands/wallet.js +357 -459
  125. package/dist/config.d.ts +60 -9
  126. package/dist/config.js +252 -82
  127. package/dist/constants.d.ts +29 -4
  128. package/dist/constants.js +62 -20
  129. package/dist/dashboard/server.d.ts +2 -0
  130. package/dist/dashboard/server.js +9 -6
  131. package/dist/dashboard/ui.js +6 -4
  132. package/dist/dashboard/ws-feeds.js +20 -8
  133. package/dist/dex-asset-map.js +5 -3
  134. package/dist/errors.d.ts +122 -0
  135. package/dist/errors.js +194 -0
  136. package/dist/event-stream.js +75 -19
  137. package/dist/evm-master-tx.d.ts +59 -0
  138. package/dist/evm-master-tx.js +154 -0
  139. package/dist/exchanges/adapter-network.d.ts +10 -0
  140. package/dist/exchanges/adapter-network.js +10 -0
  141. package/dist/exchanges/arcus/adapter.d.ts +196 -0
  142. package/dist/exchanges/arcus/adapter.js +1092 -0
  143. package/dist/exchanges/arcus/agent.d.ts +55 -0
  144. package/dist/exchanges/arcus/agent.js +188 -0
  145. package/dist/exchanges/arcus/client.d.ts +63 -0
  146. package/dist/exchanges/arcus/client.js +285 -0
  147. package/dist/exchanges/arcus/public.d.ts +65 -0
  148. package/dist/exchanges/arcus/public.js +138 -0
  149. package/dist/exchanges/arcus/signing.d.ts +176 -0
  150. package/dist/exchanges/arcus/signing.js +288 -0
  151. package/dist/exchanges/arcus/spot-chain.d.ts +60 -0
  152. package/dist/exchanges/arcus/spot-chain.js +241 -0
  153. package/dist/exchanges/arcus/spot-router.d.ts +177 -0
  154. package/dist/exchanges/arcus/spot-router.js +183 -0
  155. package/dist/exchanges/arcus/spot.d.ts +109 -0
  156. package/dist/exchanges/arcus/spot.js +645 -0
  157. package/dist/exchanges/aster-funds.d.ts +127 -0
  158. package/dist/exchanges/aster-funds.js +252 -0
  159. package/dist/exchanges/aster-nonce.d.ts +2 -0
  160. package/dist/exchanges/aster-nonce.js +107 -0
  161. package/dist/exchanges/aster-spot.d.ts +117 -0
  162. package/dist/exchanges/aster-spot.js +686 -0
  163. package/dist/exchanges/aster-typed-data.d.ts +133 -7
  164. package/dist/exchanges/aster-typed-data.js +121 -7
  165. package/dist/exchanges/aster.d.ts +240 -6
  166. package/dist/exchanges/aster.js +1139 -195
  167. package/dist/exchanges/builder-fee.d.ts +254 -0
  168. package/dist/exchanges/builder-fee.js +421 -0
  169. package/dist/exchanges/canonical-symbols.d.ts +32 -0
  170. package/dist/exchanges/canonical-symbols.js +96 -0
  171. package/dist/exchanges/capabilities.d.ts +7 -1
  172. package/dist/exchanges/capabilities.js +7 -0
  173. package/dist/exchanges/hl-signing.d.ts +165 -0
  174. package/dist/exchanges/hl-signing.js +158 -0
  175. package/dist/exchanges/hyperliquid-outcome.d.ts +211 -0
  176. package/dist/exchanges/hyperliquid-outcome.js +646 -0
  177. package/dist/exchanges/hyperliquid-spot.d.ts +44 -5
  178. package/dist/exchanges/hyperliquid-spot.js +308 -117
  179. package/dist/exchanges/hyperliquid.d.ts +462 -57
  180. package/dist/exchanges/hyperliquid.js +1575 -449
  181. package/dist/exchanges/index.d.ts +6 -0
  182. package/dist/exchanges/index.js +4 -0
  183. package/dist/exchanges/interface.d.ts +63 -10
  184. package/dist/exchanges/interface.js +18 -3
  185. package/dist/exchanges/ioc-outcome.d.ts +44 -0
  186. package/dist/exchanges/ioc-outcome.js +57 -0
  187. package/dist/exchanges/legacy-trading-v2.d.ts +39 -0
  188. package/dist/exchanges/legacy-trading-v2.js +940 -0
  189. package/dist/exchanges/lighter-public.d.ts +43 -0
  190. package/dist/exchanges/lighter-public.js +276 -0
  191. package/dist/exchanges/lighter-rh-deposit.d.ts +62 -0
  192. package/dist/exchanges/lighter-rh-deposit.js +185 -0
  193. package/dist/exchanges/lighter-signer.d.ts +123 -0
  194. package/dist/exchanges/lighter-signer.js +215 -0
  195. package/dist/exchanges/lighter-spot.d.ts +91 -13
  196. package/dist/exchanges/lighter-spot.js +595 -233
  197. package/dist/exchanges/lighter.d.ts +611 -39
  198. package/dist/exchanges/lighter.js +1890 -649
  199. package/dist/exchanges/ondo/adapter.d.ts +152 -0
  200. package/dist/exchanges/ondo/adapter.js +811 -0
  201. package/dist/exchanges/ondo/agent.d.ts +31 -0
  202. package/dist/exchanges/ondo/agent.js +101 -0
  203. package/dist/exchanges/ondo/client.d.ts +60 -0
  204. package/dist/exchanges/ondo/client.js +297 -0
  205. package/dist/exchanges/ondo/funds.d.ts +95 -0
  206. package/dist/exchanges/ondo/funds.js +198 -0
  207. package/dist/exchanges/ondo/public.d.ts +95 -0
  208. package/dist/exchanges/ondo/public.js +214 -0
  209. package/dist/exchanges/ondo/spot.d.ts +127 -0
  210. package/dist/exchanges/ondo/spot.js +392 -0
  211. package/dist/exchanges/outcome-interface.d.ts +140 -0
  212. package/dist/exchanges/outcome-interface.js +16 -0
  213. package/dist/exchanges/pacifica-spot.d.ts +83 -0
  214. package/dist/exchanges/pacifica-spot.js +324 -0
  215. package/dist/exchanges/pacifica-typed-data.d.ts +30 -13
  216. package/dist/exchanges/pacifica-typed-data.js +57 -9
  217. package/dist/exchanges/pacifica.d.ts +293 -4
  218. package/dist/exchanges/pacifica.js +1044 -90
  219. package/dist/exchanges/precision.d.ts +47 -0
  220. package/dist/exchanges/precision.js +209 -0
  221. package/dist/exchanges/qfex/adapter.d.ts +341 -0
  222. package/dist/exchanges/qfex/adapter.js +1386 -0
  223. package/dist/exchanges/qfex/agent.d.ts +58 -0
  224. package/dist/exchanges/qfex/agent.js +188 -0
  225. package/dist/exchanges/qfex/client.d.ts +54 -0
  226. package/dist/exchanges/qfex/client.js +138 -0
  227. package/dist/exchanges/qfex/errors.d.ts +70 -0
  228. package/dist/exchanges/qfex/errors.js +236 -0
  229. package/dist/exchanges/qfex/public.d.ts +122 -0
  230. package/dist/exchanges/qfex/public.js +268 -0
  231. package/dist/exchanges/qfex/signing.d.ts +160 -0
  232. package/dist/exchanges/qfex/signing.js +283 -0
  233. package/dist/exchanges/qfex/ws-transport.d.ts +294 -0
  234. package/dist/exchanges/qfex/ws-transport.js +798 -0
  235. package/dist/exchanges/rate-limiter.d.ts +12 -0
  236. package/dist/exchanges/rate-limiter.js +64 -0
  237. package/dist/exchanges/registry.d.ts +14 -2
  238. package/dist/exchanges/registry.js +20 -32
  239. package/dist/exchanges/slippage.d.ts +37 -0
  240. package/dist/exchanges/slippage.js +70 -0
  241. package/dist/exchanges/spot-factory.d.ts +166 -0
  242. package/dist/exchanges/spot-factory.js +431 -0
  243. package/dist/exchanges/spot-interface.d.ts +98 -4
  244. package/dist/exchanges/spot-interface.js +27 -1
  245. package/dist/exchanges/spot-result.d.ts +79 -0
  246. package/dist/exchanges/spot-result.js +273 -0
  247. package/dist/exchanges/trading-v2.d.ts +117 -0
  248. package/dist/exchanges/trading-v2.js +301 -0
  249. package/dist/exchanges/venue-types.d.ts +231 -0
  250. package/dist/exchanges/venue-types.js +87 -0
  251. package/dist/exchanges/venue.d.ts +211 -0
  252. package/dist/exchanges/venue.js +132 -0
  253. package/dist/exchanges/venues/arcus.d.ts +8 -0
  254. package/dist/exchanges/venues/arcus.js +109 -0
  255. package/dist/exchanges/venues/aster.d.ts +49 -0
  256. package/dist/exchanges/venues/aster.js +176 -0
  257. package/dist/exchanges/venues/create-helpers.d.ts +18 -0
  258. package/dist/exchanges/venues/create-helpers.js +199 -0
  259. package/dist/exchanges/venues/hyperliquid.d.ts +23 -0
  260. package/dist/exchanges/venues/hyperliquid.js +126 -0
  261. package/dist/exchanges/venues/index.d.ts +16 -0
  262. package/dist/exchanges/venues/index.js +26 -0
  263. package/dist/exchanges/venues/lighter-family.d.ts +92 -0
  264. package/dist/exchanges/venues/lighter-family.js +166 -0
  265. package/dist/exchanges/venues/lighter-rh.d.ts +7 -0
  266. package/dist/exchanges/venues/lighter-rh.js +58 -0
  267. package/dist/exchanges/venues/lighter.d.ts +6 -0
  268. package/dist/exchanges/venues/lighter.js +55 -0
  269. package/dist/exchanges/venues/ondo.d.ts +29 -0
  270. package/dist/exchanges/venues/ondo.js +136 -0
  271. package/dist/exchanges/venues/pacifica.d.ts +8 -0
  272. package/dist/exchanges/venues/pacifica.js +95 -0
  273. package/dist/exchanges/venues/qfex.d.ts +39 -0
  274. package/dist/exchanges/venues/qfex.js +140 -0
  275. package/dist/execution-log.js +10 -2
  276. package/dist/funding/legacy-public.d.ts +31 -0
  277. package/dist/funding/legacy-public.js +369 -0
  278. package/dist/funding/normalize.d.ts +28 -16
  279. package/dist/funding/normalize.js +61 -29
  280. package/dist/funding/rates.d.ts +46 -11
  281. package/dist/funding/rates.js +228 -277
  282. package/dist/guardrail/perp-guardrail.js +0 -0
  283. package/dist/index.js +156 -684
  284. package/dist/jobs.d.ts +84 -6
  285. package/dist/jobs.js +239 -41
  286. package/dist/landing.d.ts +7 -2
  287. package/dist/landing.js +19 -3
  288. package/dist/mcp-server.d.ts +14 -4
  289. package/dist/mcp-server.js +821 -403
  290. package/dist/mcp-trade-guard.d.ts +16 -0
  291. package/dist/mcp-trade-guard.js +59 -0
  292. package/dist/onchain-balances.d.ts +40 -0
  293. package/dist/onchain-balances.js +173 -0
  294. package/dist/pacifica/client.d.ts +41 -10
  295. package/dist/pacifica/client.js +167 -63
  296. package/dist/pacifica/constants.d.ts +0 -1
  297. package/dist/pacifica/constants.js +0 -5
  298. package/dist/pacifica/deposit.d.ts +30 -3
  299. package/dist/pacifica/deposit.js +119 -2
  300. package/dist/pacifica/faucet.d.ts +29 -0
  301. package/dist/pacifica/faucet.js +100 -0
  302. package/dist/pacifica/sign-tx.d.ts +15 -0
  303. package/dist/pacifica/sign-tx.js +41 -0
  304. package/dist/pacifica/types/account.d.ts +28 -4
  305. package/dist/pacifica/types/lake.d.ts +20 -5
  306. package/dist/pacifica/types/lake.js +4 -0
  307. package/dist/pacifica/types/market.d.ts +5 -0
  308. package/dist/pacifica/types/order.d.ts +4 -1
  309. package/dist/pacifica/types/position.d.ts +9 -1
  310. package/dist/plan-executor.d.ts +10 -5
  311. package/dist/plan-executor.js +165 -54
  312. package/dist/position-history.js +13 -0
  313. package/dist/rebalance.d.ts +26 -2
  314. package/dist/rebalance.js +86 -7
  315. package/dist/relay-swap.d.ts +232 -0
  316. package/dist/relay-swap.js +630 -0
  317. package/dist/risk.js +5 -1
  318. package/dist/secret-env.d.ts +15 -0
  319. package/dist/secret-env.js +36 -0
  320. package/dist/settings.d.ts +169 -6
  321. package/dist/settings.js +219 -38
  322. package/dist/signer/ows-evm.d.ts +13 -0
  323. package/dist/signer/ows-evm.js +22 -0
  324. package/dist/smart-order.d.ts +9 -0
  325. package/dist/smart-order.js +53 -8
  326. package/dist/strategies/dca.d.ts +6 -2
  327. package/dist/strategies/dca.js +66 -26
  328. package/dist/strategies/funding-arb.d.ts +11 -1
  329. package/dist/strategies/funding-arb.js +202 -89
  330. package/dist/strategies/grid.d.ts +31 -0
  331. package/dist/strategies/grid.js +89 -11
  332. package/dist/strategies/pending-stop.d.ts +8 -0
  333. package/dist/strategies/pending-stop.js +12 -0
  334. package/dist/strategies/split-order.d.ts +45 -17
  335. package/dist/strategies/split-order.js +157 -91
  336. package/dist/strategies/trailing-stop.d.ts +2 -1
  337. package/dist/strategies/trailing-stop.js +52 -6
  338. package/dist/strategies/twap.d.ts +6 -1
  339. package/dist/strategies/twap.js +39 -11
  340. package/dist/trade-validator.d.ts +22 -0
  341. package/dist/trade-validator.js +119 -15
  342. package/dist/utils/numeric.d.ts +46 -0
  343. package/dist/utils/numeric.js +79 -0
  344. package/dist/utils.d.ts +19 -0
  345. package/dist/utils.js +96 -19
  346. package/dist/withdraw-gate.d.ts +49 -0
  347. package/dist/withdraw-gate.js +131 -0
  348. package/package.json +15 -6
  349. package/skills/perp-cli/SKILL.md +159 -55
  350. package/skills/perp-cli/references/agent-operations.md +112 -58
  351. package/skills/perp-cli/references/commands.md +269 -73
  352. package/skills/perp-cli/references/strategies.md +34 -31
  353. package/skills/perp-cli/scripts/arb-monitor.sh +10 -5
  354. package/skills/perp-cli/scripts/funding-analysis.sh +14 -9
  355. package/skills/perp-cli/scripts/preflight.sh +21 -14
  356. package/skills/perp-cli/scripts/spot-perp-scan.sh +12 -7
  357. package/skills/perp-cli/scripts/validate-arb.sh +31 -15
  358. package/vendor/lighter-signer/SHA256SUMS +2 -0
  359. package/vendor/lighter-signer/VERSION +8 -0
  360. package/vendor/lighter-signer/lighter-signer.wasm +0 -0
  361. package/vendor/lighter-signer/wasm_exec.js +575 -0
  362. package/dist/bot/strategies/funding-arb-v2-strategy.d.ts +0 -42
  363. package/dist/bot/strategies/funding-arb-v2-strategy.js +0 -864
@@ -0,0 +1,16 @@
1
+ import { type ExecutionRecord } from "./execution-log.js";
2
+ import type { ExchangeAdapter } from "./exchanges/interface.js";
3
+ import type { Network } from "./exchanges/venue-types.js";
4
+ /** Refuse a reduce-only order up front on a venue whose reduce-only orders are gated (uniform CAPABILITY_UNSUPPORTED). */
5
+ export declare function mcpReduceOnlyGate(adapter: ExchangeAdapter): void;
6
+ /** PERP_NETWORK → network. Unset = "mainnet" (documented default); any other value must parse. */
7
+ export declare function resolveMcpNetwork(env: string | undefined): Network;
8
+ /** Pre-send gate for an MCP order: quarantine (non-reduce-only), then local risk limits (never forced). */
9
+ export declare function mcpPreTradeGate(adapter: ExchangeAdapter, p: {
10
+ symbol: string;
11
+ size: number;
12
+ price: number | null;
13
+ reduceOnly: boolean;
14
+ }, log: (msg: string) => void): Promise<void>;
15
+ /** Execution-log entry for an MCP order (source + network recorded in meta). */
16
+ export declare function logMcpExecution(network: Network, record: Omit<ExecutionRecord, "id" | "timestamp" | "dryRun">): ExecutionRecord;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * MCP write-path safety (review N4): the MCP `trade_execute` / `trade_close` tools go through
3
+ * the same gates as `perp trade`:
4
+ *
5
+ * - network: PERP_NETWORK, validated by the same parser as `-n` (unset = mainnet, the
6
+ * documented default — never a silent substitution for an invalid value);
7
+ * - quarantine: a non-reduce-only order on a quarantined symbol is refused (an earlier
8
+ * unknown outcome must be resolved by a human first);
9
+ * - local risk limits: enforceOrderRisk with force=false — there is NO force override over
10
+ * MCP (an agent must not be able to bypass the user's limits);
11
+ * - execution log: every placed / failed order is appended to ~/.perp/executions.jsonl,
12
+ * tagged source "mcp" and the network;
13
+ * - venue gates: a reduce-only order (trade_execute reduceOnly, trade_close) on a venue whose
14
+ * reduce-only orders are currently refused (none today) fails with the uniform
15
+ * CAPABILITY_UNSUPPORTED before any read or send (mcpReduceOnlyGate).
16
+ */
17
+ import { parseNetwork } from "./cli-flags.js";
18
+ import { PerpError } from "./errors.js";
19
+ import { logExecution } from "./execution-log.js";
20
+ import { quarantineEntryFor } from "./bot/quarantine.js";
21
+ import { enforceOrderRisk } from "./trade-validator.js";
22
+ import { reduceOnlyGateOf } from "./exchanges/trading-v2.js";
23
+ /** Refuse a reduce-only order up front on a venue whose reduce-only orders are gated (uniform CAPABILITY_UNSUPPORTED). */
24
+ export function mcpReduceOnlyGate(adapter) {
25
+ const gate = reduceOnlyGateOf(adapter);
26
+ if (gate !== null)
27
+ throw gate;
28
+ }
29
+ /** PERP_NETWORK → network. Unset = "mainnet" (documented default); any other value must parse. */
30
+ export function resolveMcpNetwork(env) {
31
+ if (env === undefined)
32
+ return "mainnet";
33
+ return parseNetwork(env);
34
+ }
35
+ /** Pre-send gate for an MCP order: quarantine (non-reduce-only), then local risk limits (never forced). */
36
+ export async function mcpPreTradeGate(adapter, p, log) {
37
+ if (p.reduceOnly)
38
+ mcpReduceOnlyGate(adapter);
39
+ if (!p.reduceOnly) {
40
+ const q = quarantineEntryFor(p.symbol, log);
41
+ if (q !== null) {
42
+ throw new PerpError("RISK_VIOLATION", `${p.symbol} is quarantined by ${q.strategy}: ${q.reason}`, {
43
+ exchange: adapter.name,
44
+ remediation: `${q.remediation} — only reduce-only orders are accepted until a human clears it (perp strategy quarantine-clear ${p.symbol})`,
45
+ });
46
+ }
47
+ }
48
+ await enforceOrderRisk(adapter, {
49
+ symbol: p.symbol,
50
+ size: p.size,
51
+ ...(p.price !== null ? { price: p.price } : {}),
52
+ reduceOnly: p.reduceOnly,
53
+ force: false,
54
+ });
55
+ }
56
+ /** Execution-log entry for an MCP order (source + network recorded in meta). */
57
+ export function logMcpExecution(network, record) {
58
+ return logExecution({ ...record, dryRun: false, meta: { ...(record.meta ?? {}), source: "mcp", network } });
59
+ }
@@ -0,0 +1,40 @@
1
+ export interface OnchainBalance {
2
+ /** Chain id in perp-cli terms (arbitrum, ethereum, base, bsc, robinhood, solana, …). */
3
+ chain: string;
4
+ token: string;
5
+ kind: "stable" | "native";
6
+ /** Decimal string; null = the read failed (see `error`). */
7
+ balance: string | null;
8
+ /** Stablecoins at $1; native tokens at the Hyperliquid mid; null when unknown. */
9
+ usdValue: number | null;
10
+ /** Why the balance read failed (balance null). */
11
+ error: string | null;
12
+ /** Why a native token's usdValue is null although its balance was read. */
13
+ priceError: string | null;
14
+ }
15
+ interface TokenPin {
16
+ symbol: string;
17
+ address: string;
18
+ decimals: number;
19
+ }
20
+ interface EvmChainPin {
21
+ label: string;
22
+ chainId: number;
23
+ rpcUrl: string;
24
+ native: string;
25
+ tokens: TokenPin[];
26
+ }
27
+ /** Mainnet EVM chains, in display order. */
28
+ export declare function mainnetEvmChains(): Record<string, EvmChainPin>;
29
+ /** Per-request timeout of every read here: a stuck public RPC becomes a per-row error, not a hang. */
30
+ export declare const ONCHAIN_READ_TIMEOUT_MS = 10000;
31
+ /** Gas token + stablecoins on every EVM chain (mainnet), or Arbitrum Sepolia (testnet). `only` limits the chains. */
32
+ export declare function evmOnchainBalances(address: string, testnet: boolean, only?: readonly string[]): Promise<OnchainBalance[]>;
33
+ /** SOL + USDC / USDT (mainnet) or USDP (devnet) of a Solana address. */
34
+ export declare function solanaOnchainBalances(address: string, testnet: boolean): Promise<OnchainBalance[]>;
35
+ /** Sum of the stablecoin balances that were read (failed reads are excluded and listed in `errors`). */
36
+ export declare function stableTotal(rows: readonly OnchainBalance[]): {
37
+ usd: number;
38
+ errors: string[];
39
+ };
40
+ export {};
@@ -0,0 +1,173 @@
1
+ /**
2
+ * On-chain wallet balances (`perp wallet balance`): the gas token plus the USD stablecoins
3
+ * (USDC / USDT; USDG on Robinhood Chain) on every chain perp-cli moves funds on.
4
+ *
5
+ * Token pins come from the registries the fund-movement code already uses (RELAY_CHAINS,
6
+ * ONDO_DEPOSIT_CHAINS); the two not in them are Tether's Ethereum USDT and Solana USDT
7
+ * (tether.to/en/supported-protocols). A read that fails is reported per token
8
+ * (balance null + error) — never shown as 0.
9
+ */
10
+ import { HYPERLIQUID_API_URL } from "./api/public/urls.js";
11
+ import { ONDO_DEPOSIT_CHAINS } from "./exchanges/venues/ondo.js";
12
+ import { RELAY_CHAINS } from "./relay-swap.js";
13
+ const relayToken = (chain, symbol) => {
14
+ const a = RELAY_CHAINS[chain]?.assets[symbol];
15
+ if (a === undefined)
16
+ throw new Error(`RELAY_CHAINS has no ${symbol} on ${chain}`);
17
+ return { symbol, address: a.address, decimals: a.decimals };
18
+ };
19
+ const relayRpc = (chain) => {
20
+ const url = RELAY_CHAINS[chain]?.rpcUrl;
21
+ if (url === null || url === undefined)
22
+ throw new Error(`RELAY_CHAINS has no RPC for ${chain}`);
23
+ return url;
24
+ };
25
+ /** Mainnet EVM chains, in display order. */
26
+ export function mainnetEvmChains() {
27
+ return {
28
+ arbitrum: {
29
+ label: "Arbitrum", chainId: 42161, rpcUrl: relayRpc("arbitrum"), native: "ETH",
30
+ tokens: [relayToken("arbitrum", "USDC"), relayToken("arbitrum", "USDT")],
31
+ },
32
+ ethereum: {
33
+ label: "Ethereum", chainId: 1, rpcUrl: ONDO_DEPOSIT_CHAINS.ethereum.rpcUrl, native: "ETH",
34
+ tokens: [
35
+ { symbol: "USDC", address: ONDO_DEPOSIT_CHAINS.ethereum.usdc, decimals: 6 },
36
+ { symbol: "USDT", address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6 },
37
+ ],
38
+ },
39
+ base: {
40
+ label: "Base", chainId: 8453, rpcUrl: relayRpc("base"), native: "ETH",
41
+ tokens: [relayToken("base", "USDC")],
42
+ },
43
+ bsc: {
44
+ label: "BNB Chain", chainId: 56, rpcUrl: relayRpc("bsc"), native: "BNB",
45
+ tokens: [relayToken("bsc", "USDT"), relayToken("bsc", "USDC")],
46
+ },
47
+ robinhood: {
48
+ label: "Robinhood Chain", chainId: 4663, rpcUrl: relayRpc("robinhood"), native: "ETH",
49
+ tokens: [relayToken("robinhood", "USDG")],
50
+ },
51
+ };
52
+ }
53
+ const TESTNET_EVM_CHAINS = {
54
+ "arbitrum-sepolia": {
55
+ label: "Arbitrum Sepolia", chainId: 421614, rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc", native: "ETH",
56
+ tokens: [{ symbol: "USDC", address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d", decimals: 6 }],
57
+ },
58
+ };
59
+ /** Built on use (not at import) so a registry change can only break `wallet balance`, never startup. */
60
+ function solanaPins(testnet) {
61
+ return testnet
62
+ ? { rpcUrl: "https://api.devnet.solana.com", tokens: [{ symbol: "USDP", address: "USDPqRbLidFGufty2s3oizmDEKdqx7ePTqzDMbf5ZKM", decimals: 6 }] }
63
+ : {
64
+ rpcUrl: "https://api.mainnet-beta.solana.com",
65
+ tokens: [
66
+ { symbol: "USDC", address: relayToken("solana", "USDC").address, decimals: 6 },
67
+ { symbol: "USDT", address: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", decimals: 6 },
68
+ ],
69
+ };
70
+ }
71
+ /** Per-request timeout of every read here: a stuck public RPC becomes a per-row error, not a hang. */
72
+ export const ONCHAIN_READ_TIMEOUT_MS = 10_000;
73
+ const timedFetch = (input, init) => fetch(input, { ...init, signal: AbortSignal.timeout(ONCHAIN_READ_TIMEOUT_MS) });
74
+ const errText = (e) => (e instanceof Error ? e.message : String(e)).slice(0, 160);
75
+ /**
76
+ * USD mids of the native gas tokens from Hyperliquid allMids. A failed / missing price leaves the
77
+ * native row's usdValue null and names the reason in `priceError`; balances are unaffected.
78
+ */
79
+ async function nativePrices() {
80
+ const px = new Map();
81
+ try {
82
+ const res = await timedFetch(HYPERLIQUID_API_URL, {
83
+ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ type: "allMids" }),
84
+ });
85
+ if (!res.ok)
86
+ return { px, error: `Hyperliquid allMids HTTP ${res.status}` };
87
+ const mids = await res.json();
88
+ for (const sym of ["ETH", "BNB", "SOL"]) {
89
+ const v = Number(mids[sym]);
90
+ if (typeof mids[sym] === "string" && Number.isFinite(v) && v > 0)
91
+ px.set(sym, v);
92
+ }
93
+ return { px, error: null };
94
+ }
95
+ catch (e) {
96
+ return { px, error: `Hyperliquid allMids: ${errText(e)}` };
97
+ }
98
+ }
99
+ function row(chain, token, kind, balance, prices, error) {
100
+ let usdValue = null;
101
+ let priceError = null;
102
+ if (balance !== null) {
103
+ if (kind === "stable")
104
+ usdValue = Number(balance);
105
+ else if (prices.px.has(token))
106
+ usdValue = Number(balance) * prices.px.get(token);
107
+ else
108
+ priceError = prices.error ?? `no Hyperliquid mid for ${token}`;
109
+ }
110
+ return { chain, token, kind, balance, usdValue, error, priceError };
111
+ }
112
+ async function evmChainBalances(ethers, chain, pin, address, prices) {
113
+ const req = new ethers.FetchRequest(pin.rpcUrl);
114
+ req.timeout = ONCHAIN_READ_TIMEOUT_MS;
115
+ // batchMaxCount 1: one plain JSON-RPC call per read (not every public RPC accepts batches).
116
+ const provider = new ethers.JsonRpcProvider(req, pin.chainId, { staticNetwork: true, batchMaxCount: 1 });
117
+ const native = provider.getBalance(address)
118
+ .then(b => row(chain, pin.native, "native", ethers.formatEther(b), prices, null))
119
+ .catch(e => row(chain, pin.native, "native", null, prices, errText(e)));
120
+ const tokens = pin.tokens.map(t => {
121
+ const c = new ethers.Contract(t.address, ["function balanceOf(address) view returns (uint256)"], provider);
122
+ return c.balanceOf(address)
123
+ .then(b => row(chain, t.symbol, "stable", ethers.formatUnits(b, t.decimals), prices, null))
124
+ .catch(e => row(chain, t.symbol, "stable", null, prices, errText(e)));
125
+ });
126
+ return Promise.all([native, ...tokens]);
127
+ }
128
+ /** Gas token + stablecoins on every EVM chain (mainnet), or Arbitrum Sepolia (testnet). `only` limits the chains. */
129
+ export async function evmOnchainBalances(address, testnet, only) {
130
+ const chains = testnet ? TESTNET_EVM_CHAINS : mainnetEvmChains();
131
+ const selected = Object.entries(chains).filter(([id]) => only === undefined || only.includes(id));
132
+ const [{ ethers }, prices] = await Promise.all([import("ethers"), nativePrices()]);
133
+ return (await Promise.all(selected.map(([id, pin]) => evmChainBalances(ethers, id, pin, address, prices)))).flat();
134
+ }
135
+ /** SOL + USDC / USDT (mainnet) or USDP (devnet) of a Solana address. */
136
+ export async function solanaOnchainBalances(address, testnet) {
137
+ const { Connection, PublicKey } = await import("@solana/web3.js");
138
+ const cfg = solanaPins(testnet);
139
+ const chain = testnet ? "solana-devnet" : "solana";
140
+ const connection = new Connection(cfg.rpcUrl, { fetch: timedFetch });
141
+ const owner = new PublicKey(address);
142
+ const prices = await nativePrices();
143
+ const sol = connection.getBalance(owner)
144
+ .then(l => row(chain, "SOL", "native", (l / 1e9).toFixed(9).replace(/\.?0+$/, ""), prices, null))
145
+ .catch(e => row(chain, "SOL", "native", null, prices, errText(e)));
146
+ const tokens = cfg.tokens.map(t => connection.getParsedTokenAccountsByOwner(owner, { mint: new PublicKey(t.address) })
147
+ .then(res => {
148
+ let raw = 0n;
149
+ for (const { account } of res.value) {
150
+ const amount = account.data.parsed?.info?.tokenAmount?.amount;
151
+ if (typeof amount !== "string")
152
+ throw new Error(`token account without a raw amount for ${t.symbol}`);
153
+ raw += BigInt(amount);
154
+ }
155
+ const s = raw.toString().padStart(t.decimals + 1, "0");
156
+ const dec = `${s.slice(0, -t.decimals)}.${s.slice(-t.decimals)}`.replace(/\.?0+$/, "");
157
+ return row(chain, t.symbol, "stable", dec, prices, null);
158
+ })
159
+ .catch(e => row(chain, t.symbol, "stable", null, prices, errText(e))));
160
+ return Promise.all([sol, ...tokens]);
161
+ }
162
+ /** Sum of the stablecoin balances that were read (failed reads are excluded and listed in `errors`). */
163
+ export function stableTotal(rows) {
164
+ let usd = 0;
165
+ const errors = [];
166
+ for (const r of rows) {
167
+ if (r.error !== null)
168
+ errors.push(`${r.chain} ${r.token}: ${r.error}`);
169
+ else if (r.kind === "stable")
170
+ usd += Number(r.balance);
171
+ }
172
+ return { usd, errors };
173
+ }
@@ -1,21 +1,47 @@
1
1
  import { type Network } from "./constants.js";
2
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";
3
3
  type SignMessageFn = (message: Uint8Array) => Promise<Uint8Array>;
4
+ /** Per-request timeout of a POST (fetch + body read). */
5
+ export declare const PACIFICA_POST_TIMEOUT_MS = 15000;
4
6
  export interface PacificaClientConfig {
5
7
  network?: Network;
6
8
  baseUrl?: string;
7
9
  apiKey?: string;
8
- builderCode?: string;
9
10
  }
10
11
  export declare class PacificaClient {
11
12
  private baseUrl;
12
13
  private apiKey?;
13
- private builderCode;
14
+ /**
15
+ * Agent-wallet pubkey for the current request signer, set by the adapter when an
16
+ * agent wallet (not the master) is signing. When present, signed bodies carry the
17
+ * `agent_wallet` field (with account = master) so Pacifica verifies the signature
18
+ * against the agent key. Undefined for master/PK signers.
19
+ */
20
+ private requestAgentWallet?;
21
+ /** Attach (or clear) the agent wallet used for subsequent signed requests. */
22
+ setRequestAgentWallet(agentWallet?: string): void;
23
+ /** Build a signed POST body, attaching agent_wallet when an agent is the active signer. */
24
+ private signedBody;
14
25
  constructor(config?: PacificaClientConfig);
15
26
  private headers;
16
27
  private get;
28
+ /**
29
+ * Signed POST. Every path except the listing reads (READ_POST_PATHS) is an account write: once
30
+ * the request is on the wire a connection reset / timeout / 5xx / unreadable body leaves the
31
+ * outcome unknown → ORDER_PENDING (sendFailure), never a retryable network error. No connection
32
+ * at all → not sent. A 4xx is the venue's refusal and keeps the plain `POST <path> failed
33
+ * (<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;
36
+ * on a listing read a timeout is TIMEOUT and any other transport failure EXCHANGE_UNREACHABLE.
37
+ */
17
38
  private post;
18
- private addBuilderCode;
39
+ /**
40
+ * `builder_code` is attached only when the caller passes one — the adapter decides
41
+ * (settings builder.pacifica + confirmed approval, src/exchanges/builder-fee.ts).
42
+ * null = no builder code (the default, and always for spot: err 108).
43
+ */
44
+ private withBuilderCode;
19
45
  getInfo(): Promise<MarketInfo[]>;
20
46
  getPrices(): Promise<PriceInfo[]>;
21
47
  getBook(symbol: string, aggLevel?: AggLevel): Promise<Orderbook>;
@@ -26,7 +52,7 @@ export declare class PacificaClient {
26
52
  cursor?: string;
27
53
  }): Promise<unknown>;
28
54
  getAccount(account: string): Promise<AccountInfo>;
29
- getAccountSettings(account: string): Promise<AccountSettings[]>;
55
+ getAccountSettings(account: string): Promise<AccountSettings>;
30
56
  getPositions(account: string): Promise<Position[]>;
31
57
  getOrders(account: string): Promise<OrderInfo[]>;
32
58
  getOrderHistory(account: string, opts?: {
@@ -56,9 +82,9 @@ export declare class PacificaClient {
56
82
  }): Promise<unknown>;
57
83
  getOrderHistoryById(orderId: number): Promise<unknown>;
58
84
  getTWAPOrders(account: string): Promise<unknown[]>;
59
- createMarketOrder(params: MarketOrderParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
60
- createLimitOrder(params: LimitOrderParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
61
- createStopOrder(params: StopOrderParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
85
+ createMarketOrder(params: MarketOrderParams, account: string, signMessage: SignMessageFn, builderCode: string | null): Promise<unknown>;
86
+ createLimitOrder(params: LimitOrderParams, account: string, signMessage: SignMessageFn, builderCode: string | null): Promise<unknown>;
87
+ createStopOrder(params: StopOrderParams, account: string, signMessage: SignMessageFn, builderCode: string | null): Promise<unknown>;
62
88
  editOrder(params: EditOrderParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
63
89
  cancelOrder(params: CancelOrderParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
64
90
  cancelAllOrders(params: CancelAllOrdersParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
@@ -66,23 +92,28 @@ export declare class PacificaClient {
66
92
  symbol: string;
67
93
  order_id: number;
68
94
  }, account: string, signMessage: SignMessageFn): Promise<unknown>;
95
+ /** create_twap_order documents no builder_code, so a TWAP never carries one (builder-fee.ts). */
69
96
  createTWAP(params: TWAPParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
70
97
  cancelTWAP(params: CancelTWAPParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
71
- setTPSL(params: TPSLParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
98
+ setTPSL(params: TPSLParams, account: string, signMessage: SignMessageFn, builderCode: string | null): Promise<unknown>;
72
99
  updateLeverage(params: UpdateLeverageParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
73
100
  updateMarginMode(params: {
74
101
  symbol: string;
75
102
  is_isolated: boolean;
76
103
  }, account: string, signMessage: SignMessageFn): Promise<unknown>;
77
104
  withdraw(params: WithdrawParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
78
- createSubaccount(subaccountName: string, account: string, signMessage: SignMessageFn): Promise<unknown>;
79
105
  listSubaccounts(account: string, signMessage: SignMessageFn): Promise<unknown>;
80
106
  transferFunds(params: TransferFundsParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
81
107
  bindAgentWallet(agentWallet: string, account: string, signMessage: SignMessageFn): Promise<unknown>;
82
108
  listAgentWallets(account: string, signMessage: SignMessageFn): Promise<unknown>;
83
109
  revokeAgentWallet(agentWallet: string, account: string, signMessage: SignMessageFn): Promise<unknown>;
84
110
  revokeAllAgentWallets(account: string, signMessage: SignMessageFn): Promise<unknown>;
85
- createApiKey(name: string, maxFeeRate: string, account: string, signMessage: SignMessageFn): Promise<unknown>;
111
+ /**
112
+ * API Config Key (rate-limit key). Docs (api/rate-limits/api-config-keys): the request body is
113
+ * account / signature / timestamp / expiry_window only; python-sdk rest/api_config_keys.py signs
114
+ * type "create_api_key" with `signature_payload = {}`.
115
+ */
116
+ createApiKey(account: string, signMessage: SignMessageFn): Promise<unknown>;
86
117
  listApiKeys(account: string, signMessage: SignMessageFn): Promise<unknown>;
87
118
  revokeApiKey(apiKey: string, account: string, signMessage: SignMessageFn): Promise<unknown>;
88
119
  createLake(params: CreateLakeParams, account: string, signMessage: SignMessageFn): Promise<unknown>;