perp-cli 0.12.15 → 0.14.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 (361) hide show
  1. package/README.md +278 -31
  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 +286 -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 +74 -84
  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 +286 -0
  101. package/dist/commands/funds.d.ts +25 -0
  102. package/dist/commands/funds.js +939 -245
  103. package/dist/commands/history.js +72 -45
  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 +316 -337
  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 +219 -6
  166. package/dist/exchanges/aster.js +1023 -153
  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 +166 -0
  200. package/dist/exchanges/ondo/adapter.js +835 -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 +122 -0
  206. package/dist/exchanges/ondo/funds.js +290 -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 +288 -4
  218. package/dist/exchanges/pacifica.js +1013 -76
  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 +1383 -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 +34 -0
  270. package/dist/exchanges/venues/ondo.js +140 -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 +28 -0
  274. package/dist/exchanges/venues/qfex.js +132 -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 +157 -682
  284. package/dist/jobs.d.ts +84 -6
  285. package/dist/jobs.js +239 -41
  286. package/dist/landing.d.ts +14 -0
  287. package/dist/landing.js +36 -0
  288. package/dist/mcp-server.d.ts +14 -4
  289. package/dist/mcp-server.js +820 -402
  290. package/dist/mcp-trade-guard.d.ts +16 -0
  291. package/dist/mcp-trade-guard.js +59 -0
  292. package/dist/pacifica/client.d.ts +41 -10
  293. package/dist/pacifica/client.js +167 -63
  294. package/dist/pacifica/constants.d.ts +0 -1
  295. package/dist/pacifica/constants.js +0 -5
  296. package/dist/pacifica/deposit.d.ts +30 -3
  297. package/dist/pacifica/deposit.js +119 -2
  298. package/dist/pacifica/faucet.d.ts +29 -0
  299. package/dist/pacifica/faucet.js +100 -0
  300. package/dist/pacifica/sign-tx.d.ts +15 -0
  301. package/dist/pacifica/sign-tx.js +41 -0
  302. package/dist/pacifica/types/account.d.ts +28 -4
  303. package/dist/pacifica/types/lake.d.ts +20 -5
  304. package/dist/pacifica/types/lake.js +4 -0
  305. package/dist/pacifica/types/market.d.ts +5 -0
  306. package/dist/pacifica/types/order.d.ts +4 -1
  307. package/dist/pacifica/types/position.d.ts +9 -1
  308. package/dist/plan-executor.d.ts +10 -5
  309. package/dist/plan-executor.js +165 -54
  310. package/dist/position-history.js +13 -0
  311. package/dist/rebalance.d.ts +26 -2
  312. package/dist/rebalance.js +86 -7
  313. package/dist/relay-swap.d.ts +232 -0
  314. package/dist/relay-swap.js +630 -0
  315. package/dist/risk.js +5 -1
  316. package/dist/secret-env.d.ts +15 -0
  317. package/dist/secret-env.js +36 -0
  318. package/dist/settings.d.ts +169 -6
  319. package/dist/settings.js +219 -38
  320. package/dist/signer/ows-evm.d.ts +13 -0
  321. package/dist/signer/ows-evm.js +22 -0
  322. package/dist/smart-order.d.ts +9 -0
  323. package/dist/smart-order.js +53 -8
  324. package/dist/strategies/dca.d.ts +6 -2
  325. package/dist/strategies/dca.js +66 -26
  326. package/dist/strategies/funding-arb.d.ts +11 -1
  327. package/dist/strategies/funding-arb.js +202 -89
  328. package/dist/strategies/grid.d.ts +31 -0
  329. package/dist/strategies/grid.js +89 -11
  330. package/dist/strategies/pending-stop.d.ts +8 -0
  331. package/dist/strategies/pending-stop.js +12 -0
  332. package/dist/strategies/split-order.d.ts +45 -17
  333. package/dist/strategies/split-order.js +157 -91
  334. package/dist/strategies/trailing-stop.d.ts +2 -1
  335. package/dist/strategies/trailing-stop.js +52 -6
  336. package/dist/strategies/twap.d.ts +6 -1
  337. package/dist/strategies/twap.js +39 -11
  338. package/dist/trade-validator.d.ts +22 -0
  339. package/dist/trade-validator.js +119 -15
  340. package/dist/utils/numeric.d.ts +46 -0
  341. package/dist/utils/numeric.js +79 -0
  342. package/dist/utils.d.ts +19 -0
  343. package/dist/utils.js +96 -19
  344. package/dist/withdraw-gate.d.ts +49 -0
  345. package/dist/withdraw-gate.js +131 -0
  346. package/package.json +15 -6
  347. package/skills/perp-cli/SKILL.md +338 -134
  348. package/skills/perp-cli/references/agent-operations.md +181 -92
  349. package/skills/perp-cli/references/commands.md +475 -132
  350. package/skills/perp-cli/references/strategies.md +44 -38
  351. package/skills/perp-cli/scripts/arb-monitor.sh +22 -17
  352. package/skills/perp-cli/scripts/funding-analysis.sh +20 -10
  353. package/skills/perp-cli/scripts/preflight.sh +21 -14
  354. package/skills/perp-cli/scripts/spot-perp-scan.sh +12 -7
  355. package/skills/perp-cli/scripts/validate-arb.sh +33 -16
  356. package/vendor/lighter-signer/SHA256SUMS +2 -0
  357. package/vendor/lighter-signer/VERSION +8 -0
  358. package/vendor/lighter-signer/lighter-signer.wasm +0 -0
  359. package/vendor/lighter-signer/wasm_exec.js +575 -0
  360. package/dist/bot/strategies/funding-arb-v2-strategy.d.ts +0 -42
  361. package/dist/bot/strategies/funding-arb-v2-strategy.js +0 -864
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Withdraw gate for venues whose withdrawals are authorized by an API key alone — no owner
3
+ * signature (settings.withdraw.<venue>; today: qfex). Design §14.12 #8.
4
+ *
5
+ * Before such a withdrawal is sent it must pass, locally:
6
+ * 1. a gate is configured at all (absent → refused);
7
+ * 2. the destination is on the allowlist;
8
+ * 3. amount ≤ maxPerTx;
9
+ * 4. today's total (UTC day, from this machine's ledger) + amount ≤ maxPerDay.
10
+ * The adapter enforces it inside withdraw(), so no caller can skip it.
11
+ *
12
+ * What it is NOT: a defence against key theft. Someone holding the key file does not use this
13
+ * CLI. That defence is a trading key WITHOUT the withdraw permission (a separate key for
14
+ * funding). The gate limits mistakes and misdirected automation: its allowlist can only be
15
+ * changed with an interactive terminal confirmation (confirmWithdrawGateChange), never under
16
+ * --json, a pipe, the MCP server or a job.
17
+ *
18
+ * Ledger: ~/.perp/withdraw-ledger.json — amounts and addresses only (no secrets, Rule #3).
19
+ * An attempt is recorded BEFORE it is sent and removed only on a definite refusal, so an
20
+ * unknown outcome counts against the day.
21
+ */
22
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
23
+ import { resolve } from "node:path";
24
+ import { randomUUID } from "node:crypto";
25
+ import { writeKeystoreAtomic } from "./agent-wallet/venue-keystore.js";
26
+ import { PerpError } from "./errors.js";
27
+ function ledgerPath() {
28
+ const home = process.env["HOME"];
29
+ if (!home)
30
+ throw new PerpError("INVALID_PARAMS", "HOME is not set; cannot locate ~/.perp/withdraw-ledger.json");
31
+ return resolve(home, ".perp", "withdraw-ledger.json");
32
+ }
33
+ function readLedger() {
34
+ const path = ledgerPath();
35
+ if (!existsSync(path))
36
+ return []; // nothing withdrawn from this machine yet
37
+ let parsed;
38
+ try {
39
+ parsed = JSON.parse(readFileSync(path, "utf-8"));
40
+ }
41
+ catch (e) {
42
+ throw new PerpError("INVALID_PARAMS", `Invalid ${path}: not valid JSON (${e instanceof Error ? e.message : String(e)})`, {
43
+ remediation: `The daily withdraw total cannot be computed, so withdrawals are refused. Inspect ${path}; move it aside only after checking today's withdrawals on the venue`,
44
+ });
45
+ }
46
+ if (!Array.isArray(parsed) || parsed.some(e => e === null || typeof e !== "object" || typeof e.id !== "string" || typeof e.venue !== "string"
47
+ || typeof e.network !== "string" || typeof e.amount !== "string" || !Number.isFinite(Number(e.amount)) || typeof e.to !== "string" || !Number.isFinite(Date.parse(e.at)))) {
48
+ throw new PerpError("INVALID_PARAMS", `Invalid ${path}: not a list of withdraw entries`, {
49
+ remediation: `The daily withdraw total cannot be computed, so withdrawals are refused. Inspect ${path}`,
50
+ });
51
+ }
52
+ return parsed;
53
+ }
54
+ function writeLedger(entries) {
55
+ const path = ledgerPath();
56
+ const dir = resolve(path, "..");
57
+ if (!existsSync(dir))
58
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
59
+ writeKeystoreAtomic(path, JSON.stringify(entries, null, 2));
60
+ }
61
+ function utcDay(ms) {
62
+ return new Date(ms).toISOString().slice(0, 10);
63
+ }
64
+ /** Sum of the amounts attempted for venue + network on the UTC day of `nowMs`. */
65
+ export function withdrawnOnDay(venue, network, nowMs) {
66
+ const day = utcDay(nowMs);
67
+ return readLedger()
68
+ .filter(e => e.venue === venue && e.network === network && e.at.slice(0, 10) === day)
69
+ .reduce((sum, e) => sum + Number(e.amount), 0);
70
+ }
71
+ function denied(venue, why, remediation, details) {
72
+ return new PerpError("POLICY_DENIED", `${venue} withdraw refused by the local withdraw gate: ${why}`, { exchange: venue, ...details, remediation });
73
+ }
74
+ /**
75
+ * Throws POLICY_DENIED unless the withdrawal passes `gate`. Nothing is sent before this returns.
76
+ * `gate` null = settings.withdraw.<venue> is not configured.
77
+ */
78
+ export function assertWithdrawAllowed(venue, network, amount, to, gate, nowMs) {
79
+ const setHint = `Configure it in an interactive terminal: perp settings set withdraw.${venue} <address[+address…]>,<maxPerTx>,<maxPerDay>`;
80
+ if (gate === null) {
81
+ throw denied(venue, `settings.withdraw.${venue} is not configured — API-key withdrawals are off until you set an allowlist and limits`, setHint, {});
82
+ }
83
+ const n = Number(amount);
84
+ if (!Number.isFinite(n) || n <= 0)
85
+ throw new PerpError("INVALID_PARAMS", `Withdraw amount must be a positive decimal (got "${amount}")`);
86
+ if (!gate.allowlist.includes(to.toLowerCase())) {
87
+ throw denied(venue, `destination ${to} is not on the allowlist`, `Withdraw to an allowlisted address, or change the allowlist yourself. ${setHint}`, { allowlist: gate.allowlist });
88
+ }
89
+ if (n > gate.maxPerTx) {
90
+ throw denied(venue, `amount ${amount} exceeds maxPerTx ${gate.maxPerTx}`, `Withdraw at most ${gate.maxPerTx} USDC per transaction, or raise the limit. ${setHint}`, { maxPerTx: gate.maxPerTx });
91
+ }
92
+ const today = withdrawnOnDay(venue, network, nowMs);
93
+ if (today + n > gate.maxPerDay) {
94
+ throw denied(venue, `amount ${amount} plus ${today} already attempted today (UTC) exceeds maxPerDay ${gate.maxPerDay}`, `Wait for the next UTC day or raise the limit. ${setHint}`, { maxPerDay: gate.maxPerDay, withdrawnToday: today });
95
+ }
96
+ }
97
+ /** Record an attempt (call BEFORE sending). Returns its id for forgetWithdrawAttempt. */
98
+ export function recordWithdrawAttempt(venue, network, amount, to, nowMs) {
99
+ const entries = readLedger();
100
+ const id = randomUUID();
101
+ entries.push({ id, venue, network, amount, to: to.toLowerCase(), at: new Date(nowMs).toISOString() });
102
+ writeLedger(entries);
103
+ return id;
104
+ }
105
+ /** Remove an attempt the venue DEFINITELY refused (nothing left the account). */
106
+ export function forgetWithdrawAttempt(id) {
107
+ writeLedger(readLedger().filter(e => e.id !== id));
108
+ }
109
+ /**
110
+ * Confirmation for creating or changing settings.withdraw.<venue>. Only an interactive
111
+ * terminal can confirm: --json, a non-TTY stdin/stdout (pipes, the MCP server, jobs) are
112
+ * refused, and there is no --yes.
113
+ */
114
+ export async function confirmWithdrawGateChange(venue, gate, json) {
115
+ const what = `withdraw.${venue}: allow withdrawals to ${gate.allowlist.join(", ")} — up to ${gate.maxPerTx} USDC per transaction, ${gate.maxPerDay} USDC per UTC day`;
116
+ if (json || process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
117
+ throw new PerpError("POLICY_DENIED", `Changing the withdraw gate needs an interactive terminal confirmation (${what})`, {
118
+ remediation: `Run it yourself in a terminal, without --json: perp settings set withdraw.${venue} <address[+address…]>,<maxPerTx>,<maxPerDay>`,
119
+ });
120
+ }
121
+ const { createInterface } = await import("node:readline/promises");
122
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
123
+ try {
124
+ const a = (await rl.question(` ${what}.\n Anyone who can run perp on this machine can then withdraw to these addresses. Type the venue name (${venue}) to confirm: `)).trim().toLowerCase();
125
+ if (a !== venue)
126
+ throw new PerpError("INVALID_PARAMS", `withdraw.${venue} not changed — cancelled, nothing was saved`);
127
+ }
128
+ finally {
129
+ rl.close();
130
+ }
131
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "perp-cli",
3
- "version": "0.12.15",
4
- "description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster",
3
+ "version": "0.14.0",
4
+ "description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus",
5
5
  "bin": {
6
6
  "perp": "dist/index.js",
7
7
  "perp-mcp": "dist/mcp-server.js",
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
- "skills"
12
+ "skills",
13
+ "vendor/lighter-signer"
13
14
  ],
14
15
  "type": "module",
15
16
  "scripts": {
@@ -18,6 +19,9 @@
18
19
  "test": "vitest run --exclude '**/integration/**'",
19
20
  "test:integration": "vitest run -c vitest.integration.config.ts",
20
21
  "test:all": "vitest run",
22
+ "e2e": "tsx scripts/e2e/run.ts",
23
+ "e2e:typecheck": "tsc -p scripts/e2e/tsconfig.json",
24
+ "typecheck:test": "tsc -p tsconfig.test.json",
21
25
  "sync-skill-version": "node scripts/sync-skill-version.mjs",
22
26
  "prepublishOnly": "node scripts/sync-skill-version.mjs && pnpm run build"
23
27
  },
@@ -25,6 +29,12 @@
25
29
  "pacifica",
26
30
  "hyperliquid",
27
31
  "lighter",
32
+ "aster",
33
+ "lighter-rh",
34
+ "robinhood-chain",
35
+ "ondo",
36
+ "ondo-perps",
37
+ "arcus",
28
38
  "solana",
29
39
  "perps",
30
40
  "dex",
@@ -56,11 +66,9 @@
56
66
  "commander": "^13.1.0",
57
67
  "dotenv": "^16.5.0",
58
68
  "ethers": "^6.13.2",
59
- "hyperliquid": "^1.7.7",
60
69
  "ink": "^6.8.0",
61
70
  "ink-spinner": "^5.0.0",
62
71
  "ink-table": "^3.1.0",
63
- "lighter-ts-sdk": "1.0.10",
64
72
  "react": "^19.2.4",
65
73
  "tweetnacl": "^1.0.3",
66
74
  "ws": "^8.19.0",
@@ -70,10 +78,11 @@
70
78
  "devDependencies": {
71
79
  "@types/node": "^25.3.3",
72
80
  "@types/ws": "^8.18.1",
81
+ "@vitest/coverage-v8": "^4.1.6",
73
82
  "ts-morph": "^27.0.2",
74
83
  "tsup": "^8.4.0",
75
84
  "tsx": "^4.21.0",
76
85
  "typescript": "^5.7.0",
77
- "vitest": "^4.0.18"
86
+ "vitest": "^4.1.6"
78
87
  }
79
88
  }