perp-cli 0.12.17 → 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 +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 +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 +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 +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 +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 +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 +142 -55
  348. package/skills/perp-cli/references/agent-operations.md +110 -56
  349. package/skills/perp-cli/references/commands.md +266 -71
  350. package/skills/perp-cli/references/strategies.md +34 -31
  351. package/skills/perp-cli/scripts/arb-monitor.sh +10 -5
  352. package/skills/perp-cli/scripts/funding-analysis.sh +14 -9
  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 +31 -15
  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,286 @@
1
+ /**
2
+ * `funds deposit aster|ondo`, `funds withdraw aster`, `funds address-book add ondo` — fund movements
3
+ * whose on-chain leg is signed by the OWS master wallet (src/evm-master-tx.ts).
4
+ *
5
+ * Every command: `--dry-run` prints the plan and returns before any key, adapter or network is
6
+ * touched; the live path runs all read-only checks before the first signature; an outcome that
7
+ * cannot be read after a send is ORDER_PENDING (logged "unverified"), never "failed".
8
+ */
9
+ import chalk from "chalk";
10
+ import { supportsDryRun } from "../cli-flags.js";
11
+ import { cliCredentialOptsFrom } from "../config.js";
12
+ import { PerpError, parsePositiveDecimal } from "../errors.js";
13
+ import { logExecution } from "../execution-log.js";
14
+ import { unsupported } from "../exchanges/trading-v2.js";
15
+ import { getVenue, networkConfig } from "../exchanges/venue.js";
16
+ import { ASTER_FUNDS_CHAINS } from "../exchanges/venues/aster.js";
17
+ import { ONDO_DEPOSIT_CHAINS } from "../exchanges/venues/ondo.js";
18
+ import { jsonOk, printJson } from "../utils.js";
19
+ const realSleep = (ms) => new Promise(r => setTimeout(r, ms));
20
+ export function registerOnchainFundsCommands(ctx) {
21
+ const { program, funds, deposit, withdraw, isJson, isDryRun, getNetwork, getAdapterForExchange, printFundsPlan, failStatus } = ctx;
22
+ const creds = () => cliCredentialOptsFrom(program.opts());
23
+ /** Execution-log + rethrow for a failed live fund movement (unknown outcome → "unverified"). */
24
+ const logFailure = (venue, asset, side, amount, err, meta) => {
25
+ const txHash = err instanceof PerpError ? err.structured.details?.txHash : undefined;
26
+ logExecution({
27
+ type: "bridge", exchange: venue, symbol: asset, side, size: amount, status: failStatus(err), dryRun: false,
28
+ error: err instanceof Error ? err.message : String(err),
29
+ meta: { action: side, ...meta, ...(typeof txHash === "string" ? { txHash } : {}) },
30
+ });
31
+ };
32
+ // ═══ Aster deposit — vault contract on BNB Chain / Arbitrum ═══
33
+ supportsDryRun(deposit.command("aster <amount>"))
34
+ .description("Deposit USDT / USDC into Aster perps through the vault contract on BNB Chain or Arbitrum (approve + deposit; mainnet only; supports --dry-run)")
35
+ // --chain, not --network: the root -n/--network (mainnet | testnet) would swallow a subcommand --network.
36
+ .option("--chain <chain>", "Source chain: bsc | arbitrum", "bsc")
37
+ .option("--asset <asset>", "Deposit asset: USDT | USDC", "USDT")
38
+ .action(async (amount, opts) => {
39
+ const net = getNetwork();
40
+ const { requireAsterFundsNetwork, asterFundsChain, asterFundsAsset, planAsterDeposit, executeAsterDeposit, awaitAsterDepositCredit, ASTER_DEPOSIT_CREDIT_TIMEOUT_MS, ASTER_DEPOSIT_CREDIT_POLL_MS } = await import("../exchanges/aster-funds.js");
41
+ requireAsterFundsNetwork(net, "deposit");
42
+ const chain = asterFundsChain(opts.chain);
43
+ const asset = asterFundsAsset(opts.asset);
44
+ parsePositiveDecimal(amount, "amount");
45
+ const pins = ASTER_FUNDS_CHAINS[chain];
46
+ if (isDryRun()) {
47
+ return printFundsPlan({
48
+ action: "deposit", venue: "aster", network: net, asset, amount, chain: pins.label, chainId: pins.chainId,
49
+ vault: pins.vault, token: pins.tokens[asset], broker: "1 (perp account)", signer: "OWS master wallet",
50
+ steps: `approve(vault, exact amount) when the allowance is short → vault.depositFor(${asset}, forAddress = the master wallet, amount, broker 1) → Deposit event check → venue credit poll`,
51
+ checks: "eth_chainId, on-chain decimals(), supportToken, paused(), token balance, native gas, allowance, deposit simulation",
52
+ });
53
+ }
54
+ const { loadMasterEvmSigner } = await import("../evm-master-tx.js");
55
+ const signer = await loadMasterEvmSigner("aster", creds(), "Aster deposit");
56
+ const depositor = signer.getAddress();
57
+ // The venue credit is confirmed through the API wallet — required before anything is sent.
58
+ const { AsterAdapter } = await import("../exchanges/aster.js");
59
+ const adapter = await getAdapterForExchange("aster");
60
+ if (!(adapter instanceof AsterAdapter))
61
+ throw new Error("aster venue did not produce an AsterAdapter");
62
+ if (adapter.activeSignerTier !== "agent") {
63
+ throw new PerpError("AGENT_NOT_REGISTERED", "Aster deposit confirms the venue credit through an API wallet, and none is usable on this computer", {
64
+ exchange: "aster", remediation: "Approve one first (this works before the first deposit): perp wallet agent approve aster — then retry the deposit",
65
+ });
66
+ }
67
+ if (adapter.userAddress.toLowerCase() !== depositor.toLowerCase()) {
68
+ throw new PerpError("INVALID_PARAMS", `The master wallet ${depositor} is not the owner of the Aster API wallet's account (${adapter.userAddress}) — the vault credits the sender`, {
69
+ exchange: "aster", remediation: "Select the wallet that owns the Aster account (--ows <wallet>)",
70
+ });
71
+ }
72
+ const plan = await planAsterDeposit({ network: net, chain, asset, amount, depositor });
73
+ const view = {
74
+ venue: "aster", network: net, asset, amount, depositor, chain: plan.chainLabel, chainId: plan.chainId,
75
+ vault: plan.vault, token: plan.token, decimals: plan.decimals, broker: plan.broker.toString(), needsApprove: plan.needsApprove,
76
+ };
77
+ if (!isJson()) {
78
+ console.log(chalk.cyan(`\n Depositing ${amount} ${asset} into Aster perps on ${plan.chainLabel}...\n`));
79
+ console.log(` From: ${depositor}`);
80
+ console.log(` Vault: ${plan.vault}`);
81
+ if (plan.needsApprove)
82
+ console.log(chalk.gray(` Approving ${amount} ${asset} for the vault...`));
83
+ }
84
+ try {
85
+ const res = await executeAsterDeposit(plan, tx => signer.signTransaction(tx));
86
+ if (!isJson())
87
+ console.log(chalk.gray(` Deposit tx ${res.depositTxHash} confirmed (Deposit event verified). Waiting for the venue credit...`));
88
+ const credit = await awaitAsterDepositCredit(() => adapter.depositWithdrawHistory(), res.depositTxHash, {
89
+ timeoutMs: ASTER_DEPOSIT_CREDIT_TIMEOUT_MS, pollMs: ASTER_DEPOSIT_CREDIT_POLL_MS, sleep: realSleep, now: () => Date.now(),
90
+ });
91
+ logExecution({
92
+ type: "bridge", exchange: "aster", symbol: asset, side: "deposit", size: amount, status: "success", dryRun: false,
93
+ meta: { action: "deposit", method: "vault", chain, txHash: res.depositTxHash, approveTxHash: res.approveTxHash },
94
+ });
95
+ if (isJson())
96
+ return printJson(jsonOk({ ...view, ...res, method: "vault", credit: { state: credit.state, amount: credit.amount, accountType: credit.accountType } }));
97
+ console.log(chalk.green(`\n Deposit credited by Aster.`));
98
+ console.log(` Amount: ${amount} ${asset}`);
99
+ if (res.approveTxHash !== null)
100
+ console.log(` Approve: ${res.approveTxHash}`);
101
+ console.log(` TX Hash: ${res.depositTxHash}\n`);
102
+ }
103
+ catch (err) {
104
+ logFailure("aster", asset, "deposit", amount, err, { method: "vault", chain });
105
+ throw err;
106
+ }
107
+ });
108
+ // ═══ Aster withdraw — POST /fapi/v3/aster/user-withdraw ═══
109
+ {
110
+ const def = getVenue("aster");
111
+ const assets = def.capabilities?.withdrawAssets;
112
+ if (assets === null || assets === undefined || assets.length === 0)
113
+ throw new Error("aster declares no withdrawAssets but has a withdraw command");
114
+ supportsDryRun(withdraw.command("aster <amount>"))
115
+ .description(`Withdraw ${assets.join(" or ")} from Aster perps to your own address on BNB Chain or Arbitrum (mainnet only; needs an API wallet approved with --can-withdraw --ip-whitelist; supports --dry-run)`)
116
+ .option("--chain <chain>", "Destination chain: bsc | arbitrum", "bsc")
117
+ .option("--asset <asset>", `Asset to withdraw: ${assets.join(" | ")}`, assets[0])
118
+ .option("--to <address>", "Destination EVM address (must be the account's own address — the default)")
119
+ .action(async (amount, opts) => {
120
+ const asset = opts.asset.toUpperCase();
121
+ if (!assets.includes(asset)) {
122
+ throw new PerpError("INVALID_PARAMS", `Aster withdraws ${assets.join(" / ")} only (got "${opts.asset}")`, { remediation: `Use --asset ${assets.join(" or --asset ")}` });
123
+ }
124
+ const net = getNetwork();
125
+ const { requireAsterFundsNetwork, asterFundsChain } = await import("../exchanges/aster-funds.js");
126
+ requireAsterFundsNetwork(net, "withdraw");
127
+ const chain = asterFundsChain(opts.chain);
128
+ const pins = ASTER_FUNDS_CHAINS[chain];
129
+ if (!/^\d+(\.\d+)?$/.test(amount) || !(Number(amount) > 0)) {
130
+ throw new PerpError("INVALID_PARAMS", `Withdraw amount must be a positive decimal (got "${amount}")`);
131
+ }
132
+ if (isDryRun()) {
133
+ return printFundsPlan({
134
+ action: "withdraw", venue: "aster", network: net, asset, amount, chain: pins.label, chainId: pins.chainId,
135
+ destination: opts.to !== undefined ? opts.to : "the account's own address",
136
+ fee: "read from POST /fapi/v3/aster/user-withdraw-info at send time (amount must exceed it; it is taken from the amount)",
137
+ signatures: "master wallet EIP-712 \"Aster\" withdraw message + API wallet (canWithdraw, IP whitelist) request signature",
138
+ note: "POST /fapi/v3/aster/user-withdraw; Aster only pays the account's own address",
139
+ });
140
+ }
141
+ await ctx.requireMaster("aster", "Aster withdraw");
142
+ const { AsterAdapter } = await import("../exchanges/aster.js");
143
+ const adapter = await getAdapterForExchange("aster");
144
+ if (!(adapter instanceof AsterAdapter))
145
+ throw new Error("aster venue did not produce an AsterAdapter");
146
+ const owner = adapter.userAddress;
147
+ if (opts.to !== undefined && opts.to.toLowerCase() !== owner.toLowerCase()) {
148
+ throw new PerpError("INVALID_PARAMS", `Aster only withdraws to the account's own address ${owner}`, { remediation: `Omit --to (defaults to ${owner})` });
149
+ }
150
+ if (!isJson()) {
151
+ console.log(chalk.cyan(`\n Withdrawing ${amount} ${asset} from Aster...\n`));
152
+ console.log(` Destination: ${owner} (${pins.label})`);
153
+ }
154
+ try {
155
+ const result = await adapter.withdraw(amount, owner, { chain, asset });
156
+ logExecution({
157
+ type: "bridge", exchange: "aster", symbol: asset, side: "withdraw", size: amount, status: "success", dryRun: false,
158
+ meta: { action: "withdraw", destination: owner, chain, withdrawId: result.withdrawId, fee: result.fee },
159
+ });
160
+ if (isJson())
161
+ return printJson(jsonOk(result));
162
+ console.log(chalk.green(`\n Withdrawal accepted by Aster.`));
163
+ console.log(` Amount: ${amount} ${asset} (fee ${result.fee} ${asset} taken from it)`);
164
+ console.log(` Withdraw id: ${result.withdrawId}`);
165
+ console.log(chalk.gray(`\n Track it in the Aster app (Assets → History) until it arrives on ${pins.label}.\n`));
166
+ }
167
+ catch (err) {
168
+ logFailure("aster", asset, "withdraw", amount, err, { destination: owner, chain });
169
+ throw err;
170
+ }
171
+ });
172
+ }
173
+ // ═══ Ondo deposit — USDC transfer to the account's funding address ═══
174
+ supportsDryRun(deposit.command("ondo <amount>"))
175
+ .description("Deposit USDC into Ondo Perps: ERC-20 transfer to the account's funding address on Arbitrum or Ethereum (mainnet only; --probe sends a small amount first; supports --dry-run)")
176
+ .option("--chain <chain>", "Source chain: arbitrum | ethereum", "arbitrum")
177
+ .option("--probe <amount>", "Send this amount first, wait until Ondo credits it, then send the rest")
178
+ .action(async (amount, opts) => {
179
+ const net = getNetwork();
180
+ const f = await import("../exchanges/ondo/funds.js");
181
+ f.requireOndoDepositNetwork(net);
182
+ const chain = f.ondoDepositChain(opts.chain);
183
+ parsePositiveDecimal(amount, "amount");
184
+ const probe = opts.probe === undefined ? null : parsePositiveDecimal(opts.probe, "--probe");
185
+ const pins = ONDO_DEPOSIT_CHAINS[chain];
186
+ if (isDryRun()) {
187
+ return printFundsPlan({
188
+ action: "deposit", venue: "ondo", network: net, asset: "USDC", amount, chain: pins.label, chainId: pins.chainId, token: pins.usdc,
189
+ probe: probe === null ? "none (single transfer)" : probe, signer: "OWS master wallet",
190
+ destination: `first listed USDC ${chain} funding address of this account (POST /v1/wallet/deposit_address/list; provisioned only when none exists)`,
191
+ steps: probe === null
192
+ ? "USDC transfer → wait for the credit (GET /v1/wallet/deposits)"
193
+ : `USDC transfer of ${probe} (probe) → wait for the credit → USDC transfer of the remainder → wait for the credit (the remainder is NOT sent while the probe is uncredited)`,
194
+ checks: "eth_chainId, on-chain decimals(), USDC balance, ETH gas, funding address belongs to this account",
195
+ });
196
+ }
197
+ const { loadMasterEvmSigner } = await import("../evm-master-tx.js");
198
+ const signer = await loadMasterEvmSigner("ondo", creds(), "Ondo deposit");
199
+ const { OndoAdapter } = await import("../exchanges/ondo/adapter.js");
200
+ const adapter = await getAdapterForExchange("ondo");
201
+ if (!(adapter instanceof OndoAdapter))
202
+ throw new Error("ondo venue did not produce an OndoAdapter");
203
+ const client = adapter.restClient;
204
+ const funding = await f.resolveOndoDepositAddress(client, chain);
205
+ const plan = await f.planOndoDeposit({ network: net, chain, amount, probe, depositor: signer.getAddress(), funding });
206
+ const view = {
207
+ venue: "ondo", network: net, asset: "USDC", amount, probe, depositor: plan.depositor, chain: plan.chainLabel, chainId: plan.chainId,
208
+ token: plan.token, depositAddress: plan.depositAddress, accountId: plan.accountId, addressProvisioned: funding.provisioned,
209
+ };
210
+ if (!isJson()) {
211
+ console.log(chalk.cyan(`\n Depositing ${amount} USDC into Ondo Perps from ${plan.chainLabel}...\n`));
212
+ console.log(` From: ${plan.depositor}`);
213
+ console.log(` To: ${plan.depositAddress} (funding address of account ${plan.accountId}${funding.provisioned ? ", newly provisioned" : ""})`);
214
+ if (probe !== null)
215
+ console.log(chalk.gray(` Probe: ${probe} USDC first; the rest follows once it is credited.`));
216
+ }
217
+ try {
218
+ const res = await f.executeOndoDeposit(plan, tx => signer.signTransaction(tx), () => client.get("/v1/wallet/deposits", null), {
219
+ timeoutMs: f.ONDO_DEPOSIT_CREDIT_TIMEOUT_MS, pollMs: f.ONDO_DEPOSIT_CREDIT_POLL_MS, sleep: realSleep, now: () => Date.now(),
220
+ });
221
+ logExecution({
222
+ type: "bridge", exchange: "ondo", symbol: "USDC", side: "deposit", size: amount, status: "success", dryRun: false,
223
+ meta: { action: "deposit", method: "transfer", chain, depositAddress: plan.depositAddress, txHashes: res.transfers.map(t => t.txHash) },
224
+ });
225
+ if (isJson())
226
+ return printJson(jsonOk({ ...view, ...res, method: "transfer", credited: true }));
227
+ console.log(chalk.green(`\n Deposit credited by Ondo Perps.`));
228
+ for (const t of res.transfers)
229
+ console.log(` ${t.step === "probe" ? "Probe " : "Deposit"} ${t.amount} USDC: ${t.txHash}`);
230
+ console.log();
231
+ }
232
+ catch (err) {
233
+ logFailure("ondo", "USDC", "deposit", amount, err, { method: "transfer", chain, depositAddress: plan.depositAddress });
234
+ throw err;
235
+ }
236
+ });
237
+ // ═══ Address book (Ondo withdrawal destinations) ═══
238
+ const addressBook = funds.command("address-book").description("Withdrawal address book (Ondo Perps only withdraws to listed addresses)");
239
+ supportsDryRun(addressBook.command("add <venue> <address>"))
240
+ .description("Add the master wallet's own address to the Ondo Perps withdrawal address book (SIWE challenge signed by the OWS master wallet; supports --dry-run)")
241
+ .option("--label <text>", "Label of the address book entry")
242
+ .action(async (venue, address, opts) => {
243
+ const def = getVenue(venue);
244
+ if (def.id !== "ondo") {
245
+ throw unsupported(def.displayName, "address-book", "only Ondo Perps has a withdrawal address book", "perp funds address-book add ondo <address>");
246
+ }
247
+ const net = getNetwork();
248
+ if (!/^0x[0-9a-fA-F]{40}$/.test(address))
249
+ throw new PerpError("INVALID_PARAMS", `"${address}" is not an EVM address`);
250
+ const plan = {
251
+ venue: "ondo", network: net, address, label: opts.label === undefined ? null : opts.label,
252
+ steps: "POST /v1/auth/erc-4361/address_book/get_challenge → personal_sign with the OWS master wallet → POST …/complete_challenge",
253
+ };
254
+ if (isDryRun()) {
255
+ if (isJson())
256
+ return printJson(jsonOk({ dryRun: true, sent: false, action: "address-book add", ...plan }));
257
+ console.log(chalk.yellow(`\n [dry-run] Would add ${address} to the Ondo Perps address book (${net})`));
258
+ console.log(` steps: ${plan.steps}`);
259
+ console.log(chalk.gray(" Nothing was signed or sent.\n"));
260
+ return;
261
+ }
262
+ const { loadMasterEvmSigner } = await import("../evm-master-tx.js");
263
+ const signer = await loadMasterEvmSigner("ondo", creds(), "Adding an Ondo address book entry");
264
+ if (signer.getAddress().toLowerCase() !== address.toLowerCase()) {
265
+ throw new PerpError("INVALID_PARAMS", `The CLI only adds the master wallet's own address (${signer.getAddress()}) to the Ondo address book; ${address} is a different address`, {
266
+ remediation: "Add other addresses in the Ondo Perps web app (Withdraw → address book)",
267
+ });
268
+ }
269
+ const { OndoAdapter } = await import("../exchanges/ondo/adapter.js");
270
+ const adapter = await getAdapterForExchange("ondo");
271
+ if (!(adapter instanceof OndoAdapter))
272
+ throw new Error("ondo venue did not produce an OndoAdapter");
273
+ const { addOndoAddressBookEntry } = await import("../exchanges/ondo/funds.js");
274
+ const res = await addOndoAddressBookEntry(adapter.restClient, {
275
+ wallet: signer.getAddress(), restUrl: networkConfig(def, net).restUrl, label: plan.label, signMessage: m => signer.signMessage(m),
276
+ });
277
+ if (isJson())
278
+ return printJson(jsonOk({ venue: "ondo", network: net, ...res }));
279
+ if (res.alreadyListed)
280
+ console.log(chalk.green(`\n ${res.address} is already on the Ondo Perps address book.\n`));
281
+ else if (res.listed)
282
+ console.log(chalk.green(`\n Added ${res.address} to the Ondo Perps address book.\n`));
283
+ else
284
+ console.log(chalk.yellow(`\n Ondo accepted the challenge, but ${res.address} is not listed yet (a cooldown may apply). Check the Ondo Perps app before withdrawing.\n`));
285
+ });
286
+ }
@@ -1,4 +1,29 @@
1
1
  import { Command } from "commander";
2
2
  import type { ExchangeAdapter } from "../exchanges/index.js";
3
3
  import type { Network } from "../pacifica/index.js";
4
+ import { PerpError } from "../errors.js";
5
+ import "../exchanges/venues/index.js";
6
+ /**
7
+ * Execution-log status of a failed funds action: an unknown outcome (ORDER_PENDING — the request
8
+ * was sent and may have executed) is logged "unverified", never "failed".
9
+ */
10
+ export declare function fundsFailStatus(err: unknown): "failed" | "unverified";
11
+ /** A broadcast deposit whose confirmation could not be read: unknown outcome, carrying the signature. */
12
+ export declare function depositOutcomeUnknown(signature: string, e: unknown): PerpError;
13
+ /**
14
+ * Local withdraw-gate verdict for a Hyperliquid destination that is not (known to be) the account
15
+ * owner: settings.withdraw.hyperliquid allowlist + maxPerTx / maxPerDay (the QFEX gate mechanism,
16
+ * src/withdraw-gate.ts). "passes" or "would refuse: …"; never throws a POLICY_DENIED (dry runs).
17
+ */
18
+ export declare function hyperliquidGateVerdict(network: string, amount: string, destination: string, nowMs: number): string;
19
+ /**
20
+ * Enforce settings.withdraw.hyperliquid for a master-signed withdraw3 / usdSend to `destination`
21
+ * and record the attempt in the withdraw ledger BEFORE it is sent. Returns the ledger id (forget it
22
+ * only on a definite refusal), or null when the destination is the owner (no gate, no ledger).
23
+ */
24
+ export declare function hyperliquidGateEnforce(network: string, amount: string, destination: string, owner: string | null, nowMs: number): string | null;
25
+ /** Label for a chain id. An unmapped id is a programming error (covered by a unit test over every venue). */
26
+ export declare function chainLabel(chain: string): string;
27
+ /** "-e lighter: USDC → Ethereum; -e lighter-rh: USDG → Robinhood Chain" — from the venue definitions. */
28
+ export declare function lighterFamilyWithdrawSummary(): string;
4
29
  export declare function registerFundsCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean, getNetwork: () => Network, getAdapterForExchange: (exchange: string) => Promise<ExchangeAdapter>): void;