perp-cli 0.11.0 → 0.12.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 (240) hide show
  1. package/README.md +30 -25
  2. package/dist/_stderr-filter.d.ts +0 -0
  3. package/dist/_stderr-filter.js +30 -0
  4. package/dist/agent-wallet/expiry.d.ts +15 -0
  5. package/dist/agent-wallet/expiry.js +26 -0
  6. package/dist/agent-wallet/lighter-keystore.d.ts +34 -0
  7. package/dist/agent-wallet/lighter-keystore.js +232 -0
  8. package/dist/agent-wallet/passphrase.d.ts +13 -0
  9. package/dist/agent-wallet/passphrase.js +54 -0
  10. package/dist/agent-wallet/signing-strategy.d.ts +67 -0
  11. package/dist/agent-wallet/signing-strategy.js +51 -0
  12. package/dist/agent-wallet/store.d.ts +37 -0
  13. package/dist/agent-wallet/store.js +172 -0
  14. package/dist/api/public/_http.d.ts +15 -0
  15. package/dist/api/public/_http.js +24 -0
  16. package/dist/api/public/hyperliquid.js +36 -24
  17. package/dist/api/public/lighter.d.ts +7 -1
  18. package/dist/api/public/lighter.js +85 -37
  19. package/dist/api/public/pacifica.js +47 -18
  20. package/dist/bridge-engine.js +102 -49
  21. package/dist/cli-spec.js +1 -2
  22. package/dist/commands/account.js +2 -500
  23. package/dist/commands/agent.d.ts +8 -2
  24. package/dist/commands/agent.js +1903 -366
  25. package/dist/commands/alerts.js +3 -1
  26. package/dist/commands/arb/index.js +37 -7
  27. package/dist/commands/arb-auto.js +44 -11
  28. package/dist/commands/arb.js +83 -34
  29. package/dist/commands/bot.d.ts +1 -1
  30. package/dist/commands/bot.js +18 -14
  31. package/dist/commands/bridge.d.ts +1 -1
  32. package/dist/commands/bridge.js +4 -4
  33. package/dist/commands/funds.d.ts +1 -1
  34. package/dist/commands/funds.js +18 -68
  35. package/dist/commands/jobs.d.ts +1 -1
  36. package/dist/commands/jobs.js +2 -2
  37. package/dist/commands/manage.d.ts +1 -1
  38. package/dist/commands/manage.js +12 -84
  39. package/dist/commands/plan.d.ts +1 -1
  40. package/dist/commands/plan.js +2 -2
  41. package/dist/commands/portfolio.d.ts +19 -3
  42. package/dist/commands/portfolio.js +747 -163
  43. package/dist/commands/rebalance.d.ts +1 -1
  44. package/dist/commands/rebalance.js +18 -12
  45. package/dist/commands/risk.js +2 -6
  46. package/dist/commands/settings.js +30 -53
  47. package/dist/commands/trade.js +16 -15
  48. package/dist/commands/wallet.d.ts +2 -1
  49. package/dist/commands/wallet.js +756 -28
  50. package/dist/errors.d.ts +64 -0
  51. package/dist/errors.js +82 -2
  52. package/dist/event-stream.js +12 -1
  53. package/dist/exchanges/aster-typed-data.d.ts +156 -0
  54. package/dist/exchanges/aster-typed-data.js +189 -0
  55. package/dist/exchanges/aster.d.ts +60 -11
  56. package/dist/exchanges/aster.js +278 -136
  57. package/dist/exchanges/hyperliquid.d.ts +14 -0
  58. package/dist/exchanges/hyperliquid.js +84 -34
  59. package/dist/exchanges/lighter-spot.js +14 -3
  60. package/dist/exchanges/lighter.d.ts +66 -0
  61. package/dist/exchanges/lighter.js +199 -27
  62. package/dist/exchanges/pacifica-typed-data.d.ts +75 -0
  63. package/dist/exchanges/pacifica-typed-data.js +74 -0
  64. package/dist/exchanges/pacifica.d.ts +29 -1
  65. package/dist/exchanges/pacifica.js +94 -6
  66. package/dist/funding/rates.js +59 -21
  67. package/dist/guardrail/perp-guardrail.js +9 -1
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +268 -360
  70. package/dist/jobs.js +3 -1
  71. package/dist/mcp-server.js +85 -83
  72. package/dist/position-history.js +47 -4
  73. package/dist/settings.d.ts +67 -3
  74. package/dist/settings.js +1 -2
  75. package/dist/signer/ows-evm.d.ts +14 -0
  76. package/dist/signer/ows-evm.js +28 -9
  77. package/dist/smart-order.d.ts +8 -2
  78. package/dist/smart-order.js +46 -11
  79. package/dist/strategies/funding-arb.js +29 -8
  80. package/dist/trade-validator.js +30 -5
  81. package/dist/utils.d.ts +10 -0
  82. package/dist/utils.js +19 -0
  83. package/package.json +2 -2
  84. package/skills/perp-cli/SKILL.md +23 -14
  85. package/skills/perp-cli/references/agent-operations.md +6 -4
  86. package/skills/perp-cli/references/commands.md +55 -34
  87. package/skills/perp-cli/scripts/preflight.sh +4 -4
  88. package/skills/perp-cli/scripts/spot-perp-scan.sh +2 -2
  89. package/dist/__tests__/alert-logic.test.d.ts +0 -1
  90. package/dist/__tests__/alert-logic.test.js +0 -107
  91. package/dist/__tests__/arb-auto-3dex.test.d.ts +0 -1
  92. package/dist/__tests__/arb-auto-3dex.test.js +0 -397
  93. package/dist/__tests__/arb-history-stats.test.d.ts +0 -1
  94. package/dist/__tests__/arb-history-stats.test.js +0 -176
  95. package/dist/__tests__/arb-logic.test.d.ts +0 -1
  96. package/dist/__tests__/arb-logic.test.js +0 -84
  97. package/dist/__tests__/arb-manage.test.d.ts +0 -1
  98. package/dist/__tests__/arb-manage.test.js +0 -253
  99. package/dist/__tests__/arb-new-features.test.d.ts +0 -1
  100. package/dist/__tests__/arb-new-features.test.js +0 -457
  101. package/dist/__tests__/arb-sizing.test.d.ts +0 -1
  102. package/dist/__tests__/arb-sizing.test.js +0 -48
  103. package/dist/__tests__/arb-state.test.d.ts +0 -1
  104. package/dist/__tests__/arb-state.test.js +0 -284
  105. package/dist/__tests__/arb-userflow.test.d.ts +0 -1
  106. package/dist/__tests__/arb-userflow.test.js +0 -945
  107. package/dist/__tests__/arb-utils.test.d.ts +0 -1
  108. package/dist/__tests__/arb-utils.test.js +0 -264
  109. package/dist/__tests__/bot-conditions.test.d.ts +0 -1
  110. package/dist/__tests__/bot-conditions.test.js +0 -341
  111. package/dist/__tests__/client-id-tracker.test.d.ts +0 -1
  112. package/dist/__tests__/client-id-tracker.test.js +0 -137
  113. package/dist/__tests__/commands/new-atomic-commands.test.d.ts +0 -1
  114. package/dist/__tests__/commands/new-atomic-commands.test.js +0 -502
  115. package/dist/__tests__/commands/order-intent.test.d.ts +0 -1
  116. package/dist/__tests__/commands/order-intent.test.js +0 -600
  117. package/dist/__tests__/commands/trade-commands.test.d.ts +0 -1
  118. package/dist/__tests__/commands/trade-commands.test.js +0 -821
  119. package/dist/__tests__/config.test.d.ts +0 -1
  120. package/dist/__tests__/config.test.js +0 -86
  121. package/dist/__tests__/cross-chain-margin.test.d.ts +0 -1
  122. package/dist/__tests__/cross-chain-margin.test.js +0 -287
  123. package/dist/__tests__/dex-asset-map.test.d.ts +0 -1
  124. package/dist/__tests__/dex-asset-map.test.js +0 -191
  125. package/dist/__tests__/errors.test.d.ts +0 -1
  126. package/dist/__tests__/errors.test.js +0 -110
  127. package/dist/__tests__/event-stream.test.d.ts +0 -1
  128. package/dist/__tests__/event-stream.test.js +0 -276
  129. package/dist/__tests__/exchanges/interface.test.d.ts +0 -1
  130. package/dist/__tests__/exchanges/interface.test.js +0 -132
  131. package/dist/__tests__/exchanges/mock-adapter.d.ts +0 -69
  132. package/dist/__tests__/exchanges/mock-adapter.js +0 -137
  133. package/dist/__tests__/execution-log.test.d.ts +0 -1
  134. package/dist/__tests__/execution-log.test.js +0 -106
  135. package/dist/__tests__/funding-calc.test.d.ts +0 -1
  136. package/dist/__tests__/funding-calc.test.js +0 -71
  137. package/dist/__tests__/funding-history.test.d.ts +0 -1
  138. package/dist/__tests__/funding-history.test.js +0 -343
  139. package/dist/__tests__/funding-rates.test.d.ts +0 -1
  140. package/dist/__tests__/funding-rates.test.js +0 -342
  141. package/dist/__tests__/funding.test.d.ts +0 -1
  142. package/dist/__tests__/funding.test.js +0 -173
  143. package/dist/__tests__/gap-logic.test.d.ts +0 -1
  144. package/dist/__tests__/gap-logic.test.js +0 -43
  145. package/dist/__tests__/hip3-dex.test.d.ts +0 -1
  146. package/dist/__tests__/hip3-dex.test.js +0 -234
  147. package/dist/__tests__/integration/agent-features.integration.test.d.ts +0 -1
  148. package/dist/__tests__/integration/agent-features.integration.test.js +0 -553
  149. package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +0 -13
  150. package/dist/__tests__/integration/atomic-commands.integration.test.js +0 -246
  151. package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +0 -1
  152. package/dist/__tests__/integration/bridge-simulation.integration.test.js +0 -453
  153. package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +0 -1
  154. package/dist/__tests__/integration/bridge-strict.integration.test.js +0 -812
  155. package/dist/__tests__/integration/bridge.integration.test.d.ts +0 -1
  156. package/dist/__tests__/integration/bridge.integration.test.js +0 -309
  157. package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +0 -1
  158. package/dist/__tests__/integration/cli-e2e.integration.test.js +0 -202
  159. package/dist/__tests__/integration/dex-arb.integration.test.d.ts +0 -1
  160. package/dist/__tests__/integration/dex-arb.integration.test.js +0 -116
  161. package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +0 -13
  162. package/dist/__tests__/integration/envelope-consistency.integration.test.js +0 -205
  163. package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +0 -1
  164. package/dist/__tests__/integration/hip3-dex.integration.test.js +0 -147
  165. package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +0 -1
  166. package/dist/__tests__/integration/hyperliquid.integration.test.js +0 -79
  167. package/dist/__tests__/integration/lighter.integration.test.d.ts +0 -1
  168. package/dist/__tests__/integration/lighter.integration.test.js +0 -53
  169. package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +0 -9
  170. package/dist/__tests__/integration/new-commands-e2e.integration.test.js +0 -236
  171. package/dist/__tests__/integration/order-verification.integration.test.d.ts +0 -1
  172. package/dist/__tests__/integration/order-verification.integration.test.js +0 -321
  173. package/dist/__tests__/integration/pacifica.integration.test.d.ts +0 -1
  174. package/dist/__tests__/integration/pacifica.integration.test.js +0 -75
  175. package/dist/__tests__/integration/response-shapes.integration.test.d.ts +0 -1
  176. package/dist/__tests__/integration/response-shapes.integration.test.js +0 -278
  177. package/dist/__tests__/liquidity.test.d.ts +0 -1
  178. package/dist/__tests__/liquidity.test.js +0 -225
  179. package/dist/__tests__/plan-executor.test.d.ts +0 -1
  180. package/dist/__tests__/plan-executor.test.js +0 -314
  181. package/dist/__tests__/position-history.test.d.ts +0 -1
  182. package/dist/__tests__/position-history.test.js +0 -367
  183. package/dist/__tests__/retry.test.d.ts +0 -1
  184. package/dist/__tests__/retry.test.js +0 -310
  185. package/dist/__tests__/risk-assessment.test.d.ts +0 -1
  186. package/dist/__tests__/risk-assessment.test.js +0 -288
  187. package/dist/__tests__/security-adversarial.test.d.ts +0 -1
  188. package/dist/__tests__/security-adversarial.test.js +0 -574
  189. package/dist/__tests__/strategies.test.d.ts +0 -1
  190. package/dist/__tests__/strategies.test.js +0 -539
  191. package/dist/__tests__/trade-execution.test.d.ts +0 -1
  192. package/dist/__tests__/trade-execution.test.js +0 -129
  193. package/dist/__tests__/trade-validator.test.d.ts +0 -1
  194. package/dist/__tests__/trade-validator.test.js +0 -655
  195. package/dist/__tests__/utils.test.d.ts +0 -1
  196. package/dist/__tests__/utils.test.js +0 -76
  197. package/dist/arb/reconcile.d.ts +0 -28
  198. package/dist/arb/reconcile.js +0 -162
  199. package/dist/commands/alert.d.ts +0 -2
  200. package/dist/commands/alert.js +0 -421
  201. package/dist/commands/analytics.d.ts +0 -3
  202. package/dist/commands/analytics.js +0 -311
  203. package/dist/commands/arb-manage.d.ts +0 -5
  204. package/dist/commands/arb-manage.js +0 -5
  205. package/dist/commands/dashboard.d.ts +0 -3
  206. package/dist/commands/dashboard.js +0 -176
  207. package/dist/commands/deposit.d.ts +0 -4
  208. package/dist/commands/deposit.js +0 -573
  209. package/dist/commands/dex.d.ts +0 -3
  210. package/dist/commands/dex.js +0 -120
  211. package/dist/commands/env.d.ts +0 -2
  212. package/dist/commands/env.js +0 -136
  213. package/dist/commands/funding.d.ts +0 -3
  214. package/dist/commands/funding.js +0 -554
  215. package/dist/commands/gap.d.ts +0 -2
  216. package/dist/commands/gap.js +0 -305
  217. package/dist/commands/health.d.ts +0 -2
  218. package/dist/commands/health.js +0 -67
  219. package/dist/commands/multileg.d.ts +0 -16
  220. package/dist/commands/multileg.js +0 -174
  221. package/dist/commands/ows.d.ts +0 -2
  222. package/dist/commands/ows.js +0 -887
  223. package/dist/commands/pnl.d.ts +0 -12
  224. package/dist/commands/pnl.js +0 -243
  225. package/dist/commands/run.d.ts +0 -3
  226. package/dist/commands/run.js +0 -202
  227. package/dist/commands/stream.d.ts +0 -5
  228. package/dist/commands/stream.js +0 -200
  229. package/dist/commands/withdraw.d.ts +0 -3
  230. package/dist/commands/withdraw.js +0 -187
  231. package/dist/exchanges/edgex.d.ts +0 -62
  232. package/dist/exchanges/edgex.js +0 -552
  233. package/dist/exchanges/nado.d.ts +0 -52
  234. package/dist/exchanges/nado.js +0 -223
  235. package/dist/funding/index.d.ts +0 -3
  236. package/dist/funding/index.js +0 -3
  237. package/dist/retry.d.ts +0 -74
  238. package/dist/retry.js +0 -129
  239. package/dist/ws/market-feed.d.ts +0 -74
  240. package/dist/ws/market-feed.js +0 -227
@@ -1,573 +0,0 @@
1
- import chalk from "chalk";
2
- import { printJson, formatUsd, jsonOk } from "../utils.js";
3
- import { PacificaAdapter } from "../exchanges/pacifica.js";
4
- import { logExecution } from "../execution-log.js";
5
- const DEFAULT_RELAYER = "http://localhost:3100";
6
- function getRelayerUrl() {
7
- return process.env.PERP_RELAYER_URL || DEFAULT_RELAYER;
8
- }
9
- async function relayerAvailable() {
10
- try {
11
- const res = await fetch(`${getRelayerUrl()}/health`, { signal: AbortSignal.timeout(2000) });
12
- return res.ok;
13
- }
14
- catch {
15
- return false;
16
- }
17
- }
18
- export function registerDepositCommands(program, getAdapter, isJson, getNetwork) {
19
- const deposit = program.command("deposit").description("Deposit funds into exchange accounts");
20
- // ── Pacifica (Solana) ──
21
- deposit
22
- .command("pacifica <amount>")
23
- .description("Deposit USDC into Pacifica")
24
- .option("--no-relay", "Skip relayer, pay gas yourself")
25
- .action(async (amount, opts) => {
26
- const amountNum = parseFloat(amount);
27
- if (isNaN(amountNum) || amountNum <= 0)
28
- throw new Error("Invalid amount");
29
- if (amountNum < 10)
30
- throw new Error("Minimum deposit is 10 USDC");
31
- // Try relayer first (gas-sponsored)
32
- if (opts.relay && await relayerAvailable()) {
33
- if (!isJson())
34
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} via relayer (gasless)...\n`));
35
- const adapter = await getAdapter();
36
- if (!(adapter instanceof PacificaAdapter))
37
- throw new Error("Requires --exchange pacifica");
38
- try {
39
- // 1. Get sponsored TX from relayer
40
- const buildRes = await fetch(`${getRelayerUrl()}/deposit/pacifica/build`, {
41
- method: "POST",
42
- headers: { "Content-Type": "application/json" },
43
- body: JSON.stringify({
44
- userPubkey: adapter.keypair.publicKey.toBase58(),
45
- amount: amountNum,
46
- testnet: getNetwork() === "testnet",
47
- }),
48
- });
49
- if (!buildRes.ok) {
50
- const err = await buildRes.json();
51
- throw new Error(err.error || "Relayer build failed");
52
- }
53
- const { transaction, fee, netAmount } = (await buildRes.json());
54
- if (!isJson()) {
55
- console.log(` Fee: $${formatUsd(fee)} (gas sponsored)`);
56
- console.log(` Net: $${formatUsd(netAmount)} to Pacifica\n`);
57
- }
58
- // 2. User signs the TX
59
- const { Transaction } = await import("@solana/web3.js");
60
- const tx = Transaction.from(Buffer.from(transaction, "base64"));
61
- tx.partialSign(adapter.keypair);
62
- const signed = tx.serialize().toString("base64");
63
- // 3. Submit via relayer
64
- const submitRes = await fetch(`${getRelayerUrl()}/deposit/pacifica/submit`, {
65
- method: "POST",
66
- headers: { "Content-Type": "application/json" },
67
- body: JSON.stringify({
68
- signedTransaction: signed,
69
- testnet: getNetwork() === "testnet",
70
- }),
71
- });
72
- if (!submitRes.ok) {
73
- const err = await submitRes.json();
74
- throw new Error(err.error || "Submit failed");
75
- }
76
- const result = (await submitRes.json());
77
- logExecution({
78
- type: "bridge", exchange: "pacifica", symbol: "USDC", side: "deposit",
79
- size: String(amountNum), status: "success", dryRun: false,
80
- meta: { action: "deposit", method: "relay", signature: result.signature },
81
- });
82
- if (isJson())
83
- return printJson(jsonOk({ ...result, fee, netAmount, method: "relay" }));
84
- console.log(chalk.green(` Deposit confirmed!`));
85
- console.log(` Signature: ${result.signature}`);
86
- console.log(chalk.gray(`\n Gas: FREE (relayer sponsored)\n`));
87
- return;
88
- }
89
- catch (err) {
90
- logExecution({
91
- type: "bridge", exchange: "pacifica", symbol: "USDC", side: "deposit",
92
- size: String(amountNum), status: "failed", dryRun: false,
93
- error: err instanceof Error ? err.message : String(err),
94
- meta: { action: "deposit", method: "relay" },
95
- });
96
- throw err;
97
- }
98
- }
99
- // Fallback: direct deposit (user pays gas)
100
- if (!isJson()) {
101
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} USDC into Pacifica...\n`));
102
- console.log(chalk.gray(" Requires: SOL for gas (~0.005 SOL) + USDC on Solana\n"));
103
- }
104
- const adapter = await getAdapter();
105
- if (!(adapter instanceof PacificaAdapter))
106
- throw new Error("Requires --exchange pacifica");
107
- try {
108
- const { Connection, Transaction } = await import("@solana/web3.js");
109
- const { buildDepositInstruction } = await import("../pacifica/deposit.js");
110
- const network = getNetwork();
111
- const rpcUrl = network === "testnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com";
112
- const connection = new Connection(rpcUrl, "confirmed");
113
- const solBalance = await connection.getBalance(adapter.keypair.publicKey);
114
- if (solBalance < 5_000_000) {
115
- console.error(chalk.red(" Insufficient SOL for gas. Need ~0.005 SOL."));
116
- console.error(chalk.gray(" Tip: Use relayer for gasless deposits (start relayer server)\n"));
117
- process.exit(1);
118
- }
119
- // Check USDC balance before sending TX
120
- const { PublicKey } = await import("@solana/web3.js");
121
- const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
122
- const tokenAccounts = await connection.getParsedTokenAccountsByOwner(adapter.keypair.publicKey, { mint: USDC_MINT });
123
- const usdcBalance = tokenAccounts.value.length > 0
124
- ? tokenAccounts.value[0].account.data.parsed.info.tokenAmount.uiAmount ?? 0
125
- : 0;
126
- if (usdcBalance < amountNum) {
127
- console.error(chalk.red(` Insufficient USDC on Solana. Have: $${formatUsd(usdcBalance)}, need: $${formatUsd(amountNum)}`));
128
- process.exit(1);
129
- }
130
- const ix = await buildDepositInstruction(adapter.keypair.publicKey, amountNum, network);
131
- const tx = new Transaction().add(ix);
132
- tx.feePayer = adapter.keypair.publicKey;
133
- tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
134
- tx.sign(adapter.keypair);
135
- const sig = await connection.sendRawTransaction(tx.serialize());
136
- await connection.confirmTransaction(sig, "confirmed");
137
- logExecution({
138
- type: "bridge", exchange: "pacifica", symbol: "USDC", side: "deposit",
139
- size: String(amountNum), status: "success", dryRun: false,
140
- meta: { action: "deposit", method: "direct", signature: sig },
141
- });
142
- if (isJson())
143
- return printJson(jsonOk({ signature: sig, amount: amountNum, method: "direct" }));
144
- console.log(chalk.green(` Deposit confirmed!`));
145
- console.log(` Amount: $${formatUsd(amountNum)} USDC`);
146
- console.log(` Signature: ${sig}\n`);
147
- }
148
- catch (err) {
149
- logExecution({
150
- type: "bridge", exchange: "pacifica", symbol: "USDC", side: "deposit",
151
- size: String(amountNum), status: "failed", dryRun: false,
152
- error: err instanceof Error ? err.message : String(err),
153
- meta: { action: "deposit", method: "direct" },
154
- });
155
- throw err;
156
- }
157
- });
158
- // ── Hyperliquid (Arbitrum — USDC transfer to Bridge2) ──
159
- deposit
160
- .command("hyperliquid <amount>")
161
- .description("Deposit USDC into Hyperliquid (Arbitrum)")
162
- .option("--no-relay", "Skip relayer, pay gas yourself")
163
- .action(async (amount, opts) => {
164
- const amountNum = parseFloat(amount);
165
- if (isNaN(amountNum) || amountNum <= 0)
166
- throw new Error("Invalid amount");
167
- if (amountNum < 5)
168
- throw new Error("Minimum deposit is $5 for Hyperliquid");
169
- // Try relayer
170
- if (opts.relay && await relayerAvailable()) {
171
- if (!isJson())
172
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} via relayer (gasless)...\n`));
173
- const { ethers } = await import("ethers");
174
- const { loadPrivateKey } = await import("../config.js");
175
- const pk = await loadPrivateKey("hyperliquid");
176
- const wallet = new ethers.Wallet(pk);
177
- try {
178
- const res = await fetch(`${getRelayerUrl()}/deposit/hyperliquid`, {
179
- method: "POST",
180
- headers: { "Content-Type": "application/json" },
181
- body: JSON.stringify({ userAddress: wallet.address, amount: amountNum }),
182
- });
183
- const result = (await res.json());
184
- if (!res.ok)
185
- throw new Error(String(result.error || "Relayer failed"));
186
- logExecution({
187
- type: "bridge", exchange: "hyperliquid", symbol: "USDC", side: "deposit",
188
- size: String(amountNum), status: "success", dryRun: false,
189
- meta: { action: "deposit", method: "relay", txHash: String(result.txHash) },
190
- });
191
- if (isJson())
192
- return printJson(jsonOk({ ...result, method: "relay" }));
193
- console.log(chalk.green(` Deposit confirmed!`));
194
- console.log(` TX Hash: ${result.txHash}`);
195
- console.log(` Fee: $${formatUsd(Number(result.fee))}`);
196
- console.log(` Net: $${formatUsd(Number(result.netAmount))}`);
197
- console.log(chalk.gray(`\n Gas: FREE (relayer sponsored)\n`));
198
- return;
199
- }
200
- catch (err) {
201
- logExecution({
202
- type: "bridge", exchange: "hyperliquid", symbol: "USDC", side: "deposit",
203
- size: String(amountNum), status: "failed", dryRun: false,
204
- error: err instanceof Error ? err.message : String(err),
205
- meta: { action: "deposit", method: "relay" },
206
- });
207
- throw err;
208
- }
209
- }
210
- // Direct: USDC.transfer() to HL Bridge2
211
- if (!isJson()) {
212
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} USDC into Hyperliquid...\n`));
213
- console.log(chalk.gray(" Requires: ETH on Arbitrum for gas (~0.0001 ETH) + USDC on Arbitrum\n"));
214
- }
215
- const { ethers } = await import("ethers");
216
- const { loadPrivateKey } = await import("../config.js");
217
- const pk = await loadPrivateKey("hyperliquid");
218
- const provider = new ethers.JsonRpcProvider("https://arb1.arbitrum.io/rpc");
219
- const wallet = new ethers.Wallet(pk, provider);
220
- const HL_BRIDGE = "0x2Df1c51E09aECF9cacB7bc98cB1742757f163dF7";
221
- const USDC_ARB = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
222
- // Check balances
223
- const ethBal = await provider.getBalance(wallet.address);
224
- if (ethBal < ethers.parseEther("0.0001")) {
225
- console.error(chalk.red(" Insufficient ETH on Arbitrum for gas."));
226
- process.exit(1);
227
- }
228
- const usdc = new ethers.Contract(USDC_ARB, [
229
- "function transfer(address to, uint256 amount) returns (bool)",
230
- "function balanceOf(address) view returns (uint256)",
231
- ], wallet);
232
- const amountRaw = ethers.parseUnits(amount, 6);
233
- const usdcBal = await usdc.balanceOf(wallet.address);
234
- if (usdcBal < amountRaw) {
235
- console.error(chalk.red(` Insufficient USDC. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
236
- process.exit(1);
237
- }
238
- try {
239
- // Direct USDC transfer to HL Bridge2 (simplest method)
240
- if (!isJson())
241
- console.log(chalk.gray(" Sending USDC to Hyperliquid Bridge2..."));
242
- const tx = await usdc.transfer(HL_BRIDGE, amountRaw);
243
- const receipt = await tx.wait();
244
- logExecution({
245
- type: "bridge", exchange: "hyperliquid", symbol: "USDC", side: "deposit",
246
- size: String(amountNum), status: "success", dryRun: false,
247
- meta: { action: "deposit", method: "direct", txHash: receipt.hash },
248
- });
249
- if (isJson())
250
- return printJson(jsonOk({ txHash: receipt.hash, amount: amountNum, method: "direct" }));
251
- console.log(chalk.green(` Deposit confirmed!`));
252
- console.log(` Amount: $${formatUsd(amountNum)} USDC`);
253
- console.log(` TX Hash: ${receipt.hash}`);
254
- console.log(chalk.gray(`\n Funds appear in ~1-3 minutes.\n`));
255
- }
256
- catch (err) {
257
- logExecution({
258
- type: "bridge", exchange: "hyperliquid", symbol: "USDC", side: "deposit",
259
- size: String(amountNum), status: "failed", dryRun: false,
260
- error: err instanceof Error ? err.message : String(err),
261
- meta: { action: "deposit", method: "direct" },
262
- });
263
- throw err;
264
- }
265
- });
266
- // ── Lighter ──
267
- const lighterDeposit = deposit.command("lighter").description("Deposit USDC into Lighter");
268
- // Lighter via Ethereum L1 (min 1 USDC)
269
- lighterDeposit
270
- .command("ethereum <amount>")
271
- .description("Deposit USDC via Ethereum L1 (min 1 USDC, gas: $3-10+)")
272
- .option("--asset-id <id>", "Asset index (default: 2 = USDC)", "2")
273
- .option("--route <type>", "Route: 0=perps, 1=spot (default: 0)", "0")
274
- .action(async (amount, opts) => {
275
- const amountNum = parseFloat(amount);
276
- if (isNaN(amountNum) || amountNum <= 0)
277
- throw new Error("Invalid amount");
278
- if (amountNum < 1)
279
- throw new Error("Minimum deposit via Ethereum is 1 USDC");
280
- if (!isJson()) {
281
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} USDC into Lighter via Ethereum L1...\n`));
282
- console.log(chalk.yellow(" Warning: Ethereum L1 gas fees may be high ($3-10+)\n"));
283
- }
284
- const { ethers } = await import("ethers");
285
- const { loadPrivateKey } = await import("../config.js");
286
- const pk = await loadPrivateKey("lighter");
287
- const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com");
288
- const wallet = new ethers.Wallet(pk, provider);
289
- const LIGHTER_CONTRACT = "0x3B4D794a66304f130a4db8f2551b0070dfcf5ca7";
290
- const USDC_ETH = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
291
- const usdc = new ethers.Contract(USDC_ETH, [
292
- "function approve(address spender, uint256 amount) returns (bool)",
293
- "function allowance(address owner, address spender) view returns (uint256)",
294
- "function balanceOf(address) view returns (uint256)",
295
- ], wallet);
296
- const lighter = new ethers.Contract(LIGHTER_CONTRACT, [
297
- "function deposit(address _to, uint8 _assetIndex, uint8 _routeType, uint256 _amount) payable",
298
- ], wallet);
299
- const amountRaw = ethers.parseUnits(amount, 6);
300
- // Check ETH balance for gas
301
- const ethBal = await provider.getBalance(wallet.address);
302
- if (ethBal < ethers.parseEther("0.003")) {
303
- console.error(chalk.red(" Insufficient ETH on Ethereum for gas. Need ~0.003 ETH ($3+)."));
304
- process.exit(1);
305
- }
306
- // Check USDC balance
307
- const usdcBal = await usdc.balanceOf(wallet.address);
308
- if (usdcBal < amountRaw) {
309
- console.error(chalk.red(` Insufficient USDC on Ethereum. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
310
- process.exit(1);
311
- }
312
- // Approve if needed
313
- const allowance = await usdc.allowance(wallet.address, LIGHTER_CONTRACT);
314
- if (allowance < amountRaw) {
315
- if (!isJson())
316
- console.log(chalk.gray(" Approving USDC for Lighter..."));
317
- const approveTx = await usdc.approve(LIGHTER_CONTRACT, amountRaw);
318
- await approveTx.wait();
319
- if (!isJson())
320
- console.log(chalk.gray(" Approved."));
321
- }
322
- // Call deposit(address _to, uint8 _assetIndex, uint8 _routeType, uint256 _amount)
323
- if (!isJson())
324
- console.log(chalk.gray(" Calling deposit()..."));
325
- try {
326
- const tx = await lighter.deposit(wallet.address, parseInt(opts.assetId), parseInt(opts.route), amountRaw);
327
- const receipt = await tx.wait();
328
- logExecution({
329
- type: "bridge", exchange: "lighter", symbol: "USDC", side: "deposit",
330
- size: String(amountNum), status: "success", dryRun: false,
331
- meta: { action: "deposit", method: "ethereum", txHash: receipt.hash },
332
- });
333
- if (isJson())
334
- return printJson(jsonOk({ txHash: receipt.hash, amount: amountNum, chain: "ethereum", method: "direct" }));
335
- console.log(chalk.green(`\n Deposit confirmed!`));
336
- console.log(` Amount: $${formatUsd(amountNum)} USDC`);
337
- console.log(` TX Hash: ${receipt.hash}`);
338
- console.log(chalk.gray(`\n Funds appear in your Lighter perps account shortly.\n`));
339
- }
340
- catch (err) {
341
- logExecution({
342
- type: "bridge", exchange: "lighter", symbol: "USDC", side: "deposit",
343
- size: String(amountNum), status: "failed", dryRun: false,
344
- error: err instanceof Error ? err.message : String(err),
345
- meta: { action: "deposit", method: "ethereum" },
346
- });
347
- throw err;
348
- }
349
- });
350
- // Lighter via CCTP (Arbitrum, Base, Avalanche — min 5 USDC)
351
- const CCTP_CHAINS = {
352
- arbitrum: { chainId: 42161, rpc: "https://arb1.arbitrum.io/rpc", usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", name: "Arbitrum" },
353
- base: { chainId: 8453, rpc: "https://mainnet.base.org", usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", name: "Base" },
354
- avalanche: { chainId: 43114, rpc: "https://api.avax.network/ext/bc/C/rpc", usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", name: "Avalanche" },
355
- };
356
- lighterDeposit
357
- .command("cctp <chain> <amount>")
358
- .description("Deposit USDC via CCTP (arbitrum, base, avalanche — min 5 USDC)")
359
- .action(async (chain, amount) => {
360
- const amountNum = parseFloat(amount);
361
- if (isNaN(amountNum) || amountNum <= 0)
362
- throw new Error("Invalid amount");
363
- if (amountNum < 5)
364
- throw new Error("Minimum CCTP deposit is 5 USDC");
365
- const chainKey = chain.toLowerCase();
366
- const chainInfo = CCTP_CHAINS[chainKey];
367
- if (!chainInfo)
368
- throw new Error(`Unsupported chain: ${chain}. Use: arbitrum, base, avalanche`);
369
- if (!isJson())
370
- console.log(chalk.cyan(`\n Depositing $${formatUsd(amountNum)} USDC into Lighter via CCTP (${chainInfo.name})...\n`));
371
- const { ethers } = await import("ethers");
372
- const { loadPrivateKey } = await import("../config.js");
373
- const pk = await loadPrivateKey("lighter");
374
- const provider = new ethers.JsonRpcProvider(chainInfo.rpc);
375
- const wallet = new ethers.Wallet(pk, provider);
376
- // 1. Create intent address via Lighter API
377
- if (!isJson())
378
- console.log(chalk.gray(" Creating intent address..."));
379
- const intentRes = await fetch("https://mainnet.zklighter.elliot.ai/api/v1/createIntentAddress", {
380
- method: "POST",
381
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
382
- body: new URLSearchParams({
383
- chain_id: String(chainInfo.chainId),
384
- from_addr: wallet.address,
385
- amount: "0",
386
- is_external_deposit: "true",
387
- }),
388
- });
389
- if (!intentRes.ok) {
390
- const err = await intentRes.text();
391
- throw new Error(`Failed to create intent address: ${err}`);
392
- }
393
- const intentData = (await intentRes.json());
394
- const intentAddress = String(intentData.intent_address || intentData.address || "");
395
- if (!intentAddress)
396
- throw new Error("No intent address returned");
397
- if (!isJson())
398
- console.log(` Intent address: ${intentAddress}`);
399
- // 2. Check gas + USDC balance
400
- const gasBal = await provider.getBalance(wallet.address);
401
- if (gasBal < ethers.parseEther("0.00005")) {
402
- console.error(chalk.red(` Insufficient gas token on ${chainInfo.name}. Need native token for gas (~$0.01).`));
403
- process.exit(1);
404
- }
405
- const usdc = new ethers.Contract(chainInfo.usdc, [
406
- "function transfer(address to, uint256 amount) returns (bool)",
407
- "function balanceOf(address) view returns (uint256)",
408
- ], wallet);
409
- const amountRaw = ethers.parseUnits(amount, 6);
410
- const usdcBal = await usdc.balanceOf(wallet.address);
411
- if (usdcBal < amountRaw) {
412
- console.error(chalk.red(` Insufficient USDC on ${chainInfo.name}. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
413
- process.exit(1);
414
- }
415
- // 3. Transfer USDC to intent address
416
- if (!isJson())
417
- console.log(chalk.gray(` Sending USDC to intent address on ${chainInfo.name}...`));
418
- try {
419
- const tx = await usdc.transfer(intentAddress, amountRaw);
420
- const receipt = await tx.wait();
421
- logExecution({
422
- type: "bridge", exchange: "lighter", symbol: "USDC", side: "deposit",
423
- size: String(amountNum), status: "success", dryRun: false,
424
- meta: { action: "deposit", method: "cctp", chain: chainKey, txHash: receipt.hash },
425
- });
426
- if (isJson())
427
- return printJson(jsonOk({ txHash: receipt.hash, amount: amountNum, chain: chainKey, intentAddress, method: "cctp" }));
428
- console.log(chalk.green(`\n USDC sent to intent address!`));
429
- console.log(` Amount: $${formatUsd(amountNum)} USDC`);
430
- console.log(` TX Hash: ${receipt.hash}`);
431
- console.log(` Chain: ${chainInfo.name}`);
432
- console.log(chalk.gray(`\n CCTP bridging takes ~1-3 minutes. Funds will appear in Lighter automatically.\n`));
433
- }
434
- catch (err) {
435
- logExecution({
436
- type: "bridge", exchange: "lighter", symbol: "USDC", side: "deposit",
437
- size: String(amountNum), status: "failed", dryRun: false,
438
- error: err instanceof Error ? err.message : String(err),
439
- meta: { action: "deposit", method: "cctp", chain: chainKey },
440
- });
441
- throw err;
442
- }
443
- });
444
- // Lighter deposit info
445
- lighterDeposit
446
- .command("info")
447
- .description("Show Lighter deposit routes & minimums")
448
- .action(async () => {
449
- if (isJson()) {
450
- return printJson(jsonOk({
451
- routes: {
452
- ethereum: { min: "1 USDC", gas: "$3-10+", method: "deposit() on L1 contract" },
453
- arbitrum: { min: "5 USDC", gas: "~$0.01", method: "CCTP via intent address" },
454
- base: { min: "5 USDC", gas: "~$0.01", method: "CCTP via intent address" },
455
- avalanche: { min: "5 USDC", gas: "~$0.01", method: "CCTP via intent address" },
456
- },
457
- contract: "0x3B4D794a66304f130a4db8f2551b0070dfcf5ca7",
458
- }));
459
- }
460
- console.log(chalk.cyan.bold("\n Lighter Deposit Routes\n"));
461
- console.log(chalk.white.bold(" Ethereum L1") + chalk.gray(" (direct)"));
462
- console.log(` Min: 1 USDC | Gas: $3-10+`);
463
- console.log(` Command: ${chalk.green("perp deposit lighter ethereum <amount>")}`);
464
- console.log(chalk.white.bold("\n Arbitrum") + chalk.gray(" (CCTP)"));
465
- console.log(` Min: 5 USDC | Gas: ~$0.01`);
466
- console.log(` Command: ${chalk.green("perp deposit lighter cctp arbitrum <amount>")}`);
467
- console.log(chalk.white.bold("\n Base") + chalk.gray(" (CCTP)"));
468
- console.log(` Min: 5 USDC | Gas: ~$0.01`);
469
- console.log(` Command: ${chalk.green("perp deposit lighter cctp base <amount>")}`);
470
- console.log(chalk.white.bold("\n Avalanche") + chalk.gray(" (CCTP)"));
471
- console.log(` Min: 5 USDC | Gas: ~$0.01`);
472
- console.log(` Command: ${chalk.green("perp deposit lighter cctp avalanche <amount>")}`);
473
- console.log();
474
- });
475
- // ── CCTP Bridge ──
476
- deposit
477
- .command("bridge")
478
- .description("Bridge USDC between chains via CCTP V2")
479
- .requiredOption("--from <chain>", "Source chain (arbitrum, ethereum)")
480
- .requiredOption("--to <chain>", "Destination chain (arbitrum, ethereum, solana)")
481
- .requiredOption("--amount <amount>", "USDC amount")
482
- .requiredOption("--recipient <address>", "Recipient address on destination chain")
483
- .action(async (opts) => {
484
- const amountNum = parseFloat(opts.amount);
485
- if (isNaN(amountNum) || amountNum <= 0)
486
- throw new Error("Invalid amount");
487
- if (await relayerAvailable()) {
488
- if (!isJson())
489
- console.log(chalk.cyan(`\n Bridging $${formatUsd(amountNum)} USDC via CCTP V2 (${opts.from} → ${opts.to})...\n`));
490
- const res = await fetch(`${getRelayerUrl()}/bridge/cctp`, {
491
- method: "POST",
492
- headers: { "Content-Type": "application/json" },
493
- body: JSON.stringify({
494
- fromChain: opts.from,
495
- toChain: opts.to,
496
- amount: amountNum,
497
- recipient: opts.recipient,
498
- }),
499
- });
500
- const result = (await res.json());
501
- if (!res.ok)
502
- throw new Error(String(result.error || "CCTP bridge failed"));
503
- if (isJson())
504
- return printJson(jsonOk(result));
505
- console.log(chalk.green(` Burn TX submitted!`));
506
- console.log(` TX Hash: ${result.txHash}`);
507
- console.log(` Message Hash: ${result.messageHash}`);
508
- console.log(chalk.gray(`\n Waiting for Circle attestation (~1-3 min)...`));
509
- console.log(chalk.gray(` Check: perp deposit bridge-status --hash ${result.messageHash}\n`));
510
- }
511
- else {
512
- console.error(chalk.red("\n CCTP bridge requires relayer server."));
513
- console.error(chalk.gray(" Start: cd packages/relayer && pnpm start\n"));
514
- }
515
- });
516
- deposit
517
- .command("bridge-status")
518
- .description("Check CCTP bridge status")
519
- .requiredOption("--hash <messageHash>", "Message hash from bridge TX")
520
- .action(async (opts) => {
521
- const res = await fetch(`${getRelayerUrl()}/bridge/cctp/status/${opts.hash}`);
522
- const result = (await res.json());
523
- if (isJson())
524
- return printJson(jsonOk(result));
525
- console.log(chalk.cyan.bold("\n CCTP Bridge Status\n"));
526
- console.log(` Status: ${result.status === "complete" ? chalk.green("complete") : chalk.yellow(String(result.status))}`);
527
- if (result.attestation)
528
- console.log(` Attestation: ${chalk.gray("received")}`);
529
- console.log();
530
- });
531
- // ── Info ──
532
- deposit
533
- .command("info")
534
- .description("Show deposit instructions & gas requirements")
535
- .action(async () => {
536
- const hasRelay = await relayerAvailable();
537
- if (isJson()) {
538
- return printJson(jsonOk({
539
- relayer: hasRelay ? getRelayerUrl() : null,
540
- exchanges: {
541
- pacifica: { chain: "Solana", token: "USDC", min: 10, gas: "SOL ~0.005", method: "on-chain program" },
542
- hyperliquid: { chain: "Arbitrum", token: "USDC", min: 5, gas: "ETH ~0.0001", method: "USDC transfer to Bridge2" },
543
- lighter: { chain: "Ethereum L1 / Arbitrum / Base / Avalanche", token: "USDC", min: "1 (L1) or 5 (CCTP)", gas: "$3-10 (L1), ~$0.01 (CCTP)", method: "deposit() or CCTP intent" },
544
- },
545
- }));
546
- }
547
- console.log(chalk.cyan.bold("\n Deposit Instructions\n"));
548
- if (hasRelay) {
549
- console.log(chalk.green(" ✓ Relayer available — gas-free deposits!\n"));
550
- }
551
- else {
552
- console.log(chalk.yellow(" ⚠ Relayer offline — deposits will cost gas.\n"));
553
- console.log(chalk.gray(" Start relayer: cd packages/relayer && pnpm start\n"));
554
- }
555
- console.log(chalk.white.bold(" Pacifica") + chalk.gray(" (Solana)"));
556
- console.log(` Token: USDC | Min: $10 | Gas: ${hasRelay ? chalk.green("FREE") : "SOL ~0.005"}`);
557
- console.log(` Command: ${chalk.green("perp deposit pacifica <amount>")}`);
558
- console.log(chalk.white.bold("\n Hyperliquid") + chalk.gray(" (Arbitrum)"));
559
- console.log(` Token: USDC | Min: $5 | Gas: ${hasRelay ? chalk.green("FREE") : "ETH ~0.0001"}`);
560
- console.log(` Method: USDC transfer to Bridge2`);
561
- console.log(` Command: ${chalk.green("perp deposit hyperliquid <amount>")}`);
562
- console.log(chalk.white.bold("\n Lighter") + chalk.gray(" (Ethereum L1 / CCTP)"));
563
- console.log(` Token: USDC | Min: 1 (L1), 5 (CCTP)`);
564
- console.log(` L1: ${chalk.green("perp deposit lighter ethereum <amount>")} — gas $3-10+`);
565
- console.log(` CCTP: ${chalk.green("perp deposit lighter cctp <chain> <amount>")} — gas ~$0.01`);
566
- console.log(` Chains: arbitrum, base, avalanche`);
567
- console.log(` Info: ${chalk.green("perp deposit lighter info")}`);
568
- console.log(chalk.white.bold("\n CCTP Bridge") + chalk.gray(" (Cross-chain USDC)"));
569
- console.log(` Routes: Arbitrum ↔ Ethereum ↔ Solana`);
570
- console.log(` Command: ${chalk.green("perp deposit bridge --from arbitrum --to solana --amount 100 --recipient <addr>")}`);
571
- console.log(chalk.gray("\n Use --no-relay to skip relayer and pay gas yourself.\n"));
572
- });
573
- }
@@ -1,3 +0,0 @@
1
- import { Command } from "commander";
2
- import type { ExchangeAdapter } from "../exchanges/interface.js";
3
- export declare function registerDexCommands(program: Command, getAdapter: () => Promise<ExchangeAdapter>, isJson: () => boolean): void;