perp-cli 0.7.8 → 0.7.10
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.
- package/dist/bot/engine.js +8 -0
- package/dist/bot/tui/BotDashboard.js +2 -2
- package/dist/commands/agent.js +2 -2
- package/dist/commands/bot.js +24 -2
- package/dist/commands/bridge.js +2 -2
- package/dist/commands/funds.js +55 -10
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +37 -3
- package/dist/commands/manage.js +5 -1
- package/dist/config.js +1 -1
- package/dist/pacifica/constants.d.ts +1 -1
- package/dist/pacifica/constants.js +4 -1
- package/package.json +1 -1
package/dist/bot/engine.js
CHANGED
|
@@ -365,6 +365,14 @@ async function executeActions(adapter, symbol, actions, log, dryRun = false) {
|
|
|
365
365
|
}
|
|
366
366
|
// ── Enriched snapshot ──
|
|
367
367
|
async function getEnrichedSnapshot(adapter, symbol) {
|
|
368
|
+
// Multi-symbol strategies use "ALL" — skip market-specific data
|
|
369
|
+
if (symbol.toUpperCase() === "ALL") {
|
|
370
|
+
return {
|
|
371
|
+
price: 0, high24h: 0, low24h: 0, volume24h: 0,
|
|
372
|
+
fundingRate: 0, volatility24h: 0, rsi: NaN, spreadPct: 0,
|
|
373
|
+
klines: [], orderbook: { bids: [], asks: [] }, openInterest: "0",
|
|
374
|
+
};
|
|
375
|
+
}
|
|
368
376
|
const base = await getMarketSnapshot(adapter, symbol);
|
|
369
377
|
const [orderbook, klines] = await Promise.all([
|
|
370
378
|
adapter.getOrderbook(symbol).catch(() => ({ bids: [], asks: [] })),
|
|
@@ -56,10 +56,10 @@ export function BotDashboard({ initialState, onQuit, onPause, subscribe }) {
|
|
|
56
56
|
exit();
|
|
57
57
|
}, [onQuit, exit]);
|
|
58
58
|
useInput((input, key) => {
|
|
59
|
-
if (input === "q" || (key.ctrl && input === "c")) {
|
|
59
|
+
if (input === "q" || input === "Q" || (key.ctrl && input === "c")) {
|
|
60
60
|
handleQuit();
|
|
61
61
|
}
|
|
62
|
-
if (input === "p") {
|
|
62
|
+
if (input === "p" || input === "P") {
|
|
63
63
|
setPaused((v) => !v);
|
|
64
64
|
onPause();
|
|
65
65
|
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { printJson, jsonOk } from "../utils.js";
|
|
2
|
+
import { printJson, jsonOk, jsonError } from "../utils.js";
|
|
3
3
|
import { ERROR_CODES } from "../errors.js";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
const _require = createRequire(import.meta.url);
|
|
@@ -274,7 +274,7 @@ export function registerAgentCommands(program, getAdapter, isJson) {
|
|
|
274
274
|
}
|
|
275
275
|
catch (err) {
|
|
276
276
|
const msg = err instanceof Error ? err.message : String(err);
|
|
277
|
-
console.error(JSON.stringify(
|
|
277
|
+
console.error(JSON.stringify(jsonError("EXEC_FAILED", msg)));
|
|
278
278
|
process.exit(1);
|
|
279
279
|
}
|
|
280
280
|
});
|
package/dist/commands/bot.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { printJson, jsonOk } from "../utils.js";
|
|
2
|
+
import { printJson, jsonOk, jsonError } from "../utils.js";
|
|
3
3
|
import { loadBotConfig, parseStrategy, quickGridConfig, quickDCAConfig, runBot, PRESETS, getPreset, getPresetsByStrategy } from "../bot/index.js";
|
|
4
4
|
import { updateJobState } from "../jobs.js";
|
|
5
5
|
import { runTWAP, runFundingArb, runGrid, runDCA, runTrailingStop } from "../strategies/index.js";
|
|
@@ -430,12 +430,26 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
|
|
|
430
430
|
});
|
|
431
431
|
// ── bot run <strategy> <symbol> ──
|
|
432
432
|
bot
|
|
433
|
-
.command("run
|
|
433
|
+
.command("run [strategy] [symbol]")
|
|
434
434
|
.description("Run a strategy (use 'perp bot list-strategies' to see all). Symbol optional for multi-symbol strategies.")
|
|
435
435
|
.option("--config <path>", "YAML/JSON config file")
|
|
436
436
|
.option("--headless", "Run without TUI dashboard")
|
|
437
437
|
.option("--param <key=value>", "Strategy parameter (repeatable)", (val, acc) => [...acc, val], [])
|
|
438
438
|
.action(async (strategyName, symbol, opts) => {
|
|
439
|
+
if (!strategyName) {
|
|
440
|
+
await import("../bot/engine.js");
|
|
441
|
+
const { listStrategies: listStrats } = await import("../bot/strategy-registry.js");
|
|
442
|
+
const available = listStrats();
|
|
443
|
+
if (isJson()) {
|
|
444
|
+
printJson(jsonOk({ strategies: available }));
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
console.log(chalk.cyan.bold("\n Available Strategies:\n"));
|
|
448
|
+
for (const s of available)
|
|
449
|
+
console.log(` ${chalk.green(s)}`);
|
|
450
|
+
console.log(chalk.gray(`\n Usage: perp bot run <strategy> [symbol]\n`));
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
439
453
|
const sym = symbol?.toUpperCase() || "ALL";
|
|
440
454
|
// Strategies that require an explicit symbol
|
|
441
455
|
const symbolRequiredStrategies = [
|
|
@@ -444,6 +458,10 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
|
|
|
444
458
|
"grid-mm", "liquidation-mm", "regime-mm",
|
|
445
459
|
];
|
|
446
460
|
if (sym === "ALL" && symbolRequiredStrategies.includes(strategyName)) {
|
|
461
|
+
if (isJson()) {
|
|
462
|
+
console.error(JSON.stringify(jsonError("INVALID_PARAMS", `The '${strategyName}' strategy requires a <symbol> argument`)));
|
|
463
|
+
return process.exit(1);
|
|
464
|
+
}
|
|
447
465
|
console.error(chalk.red(`\n Error: The '${strategyName}' strategy requires a <symbol> argument.`));
|
|
448
466
|
console.error(chalk.gray(` Usage: perp bot run ${strategyName} <symbol>\n`));
|
|
449
467
|
return process.exit(1);
|
|
@@ -499,6 +517,10 @@ export function registerBotCommands(program, getAdapter, getAdapterFor, isJson)
|
|
|
499
517
|
const { getStrategy, listStrategies: listStrats } = await import("../bot/strategy-registry.js");
|
|
500
518
|
if (!getStrategy(strategyName)) {
|
|
501
519
|
const available = listStrats();
|
|
520
|
+
if (isJson()) {
|
|
521
|
+
console.error(JSON.stringify(jsonError("INVALID_PARAMS", `Unknown strategy: "${strategyName}"`, { details: { available } })));
|
|
522
|
+
return process.exit(1);
|
|
523
|
+
}
|
|
502
524
|
console.error(chalk.red(`\n Unknown strategy: "${strategyName}"`));
|
|
503
525
|
console.error(chalk.gray(`\n Available strategies:`));
|
|
504
526
|
for (const s of available)
|
package/dist/commands/bridge.js
CHANGED
|
@@ -201,7 +201,7 @@ export function registerBridgeCommands(program, isJson) {
|
|
|
201
201
|
if (!gasCheck.ok) {
|
|
202
202
|
const msg = gasCheck.errors.map(e => ` ✗ ${e}`).join("\n");
|
|
203
203
|
if (isJson())
|
|
204
|
-
return printJson({ ok: false, error: "Insufficient gas", details: gasCheck.errors });
|
|
204
|
+
return printJson({ ok: false, error: { code: "INSUFFICIENT_BALANCE", message: "Insufficient gas for transaction", details: gasCheck.errors }, meta: { timestamp: new Date().toISOString() } });
|
|
205
205
|
console.log(chalk.red("\n Insufficient gas for bridge:\n"));
|
|
206
206
|
console.log(chalk.red(msg));
|
|
207
207
|
if (needsDstGas) {
|
|
@@ -343,7 +343,7 @@ export function registerBridgeCommands(program, isJson) {
|
|
|
343
343
|
if (!gasCheck.ok) {
|
|
344
344
|
const msg = gasCheck.errors.map(e => ` ✗ ${e}`).join("\n");
|
|
345
345
|
if (isJson())
|
|
346
|
-
return printJson({ ok: false, error: "Insufficient gas", details: gasCheck.errors });
|
|
346
|
+
return printJson({ ok: false, error: { code: "INSUFFICIENT_BALANCE", message: "Insufficient gas for transaction", details: gasCheck.errors }, meta: { timestamp: new Date().toISOString() } });
|
|
347
347
|
console.log(chalk.red("\n Insufficient gas for bridge:\n"));
|
|
348
348
|
console.log(chalk.red(msg));
|
|
349
349
|
if (needsDstGas) {
|
package/dist/commands/funds.js
CHANGED
|
@@ -117,8 +117,13 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
117
117
|
const connection = new Connection(rpcUrl, "confirmed");
|
|
118
118
|
const solBalance = await connection.getBalance(pacDirect.keypair.publicKey);
|
|
119
119
|
if (solBalance < 5_000_000) {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
if (isJson()) {
|
|
121
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", "Insufficient SOL for gas. Need ~0.005 SOL."));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.error(chalk.red(" Insufficient SOL for gas. Need ~0.005 SOL."));
|
|
125
|
+
console.error(chalk.gray(" Tip: Use relayer for gasless deposits (start relayer server)\n"));
|
|
126
|
+
}
|
|
122
127
|
process.exit(1);
|
|
123
128
|
}
|
|
124
129
|
const { PublicKey } = await import("@solana/web3.js");
|
|
@@ -128,7 +133,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
128
133
|
? tokenAccounts.value[0].account.data.parsed.info.tokenAmount.uiAmount ?? 0
|
|
129
134
|
: 0;
|
|
130
135
|
if (usdcBalance < amountNum) {
|
|
131
|
-
|
|
136
|
+
if (isJson()) {
|
|
137
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient USDC on Solana. Have: $${formatUsd(usdcBalance)}, need: $${formatUsd(amountNum)}`));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.error(chalk.red(` Insufficient USDC on Solana. Have: $${formatUsd(usdcBalance)}, need: $${formatUsd(amountNum)}`));
|
|
141
|
+
}
|
|
132
142
|
process.exit(1);
|
|
133
143
|
}
|
|
134
144
|
const ix = await buildDepositInstruction(pacDirect.keypair.publicKey, amountNum, network);
|
|
@@ -231,7 +241,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
231
241
|
const USDC_ARB = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
|
|
232
242
|
const ethBal = await provider.getBalance(wallet.address);
|
|
233
243
|
if (ethBal < ethers.parseEther("0.0001")) {
|
|
234
|
-
|
|
244
|
+
if (isJson()) {
|
|
245
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", "Insufficient ETH on Arbitrum for gas."));
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
console.error(chalk.red(" Insufficient ETH on Arbitrum for gas."));
|
|
249
|
+
}
|
|
235
250
|
process.exit(1);
|
|
236
251
|
}
|
|
237
252
|
const usdc = new ethers.Contract(USDC_ARB, [
|
|
@@ -241,7 +256,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
241
256
|
const amountRaw = ethers.parseUnits(amount, 6);
|
|
242
257
|
const usdcBal = await usdc.balanceOf(wallet.address);
|
|
243
258
|
if (usdcBal < amountRaw) {
|
|
244
|
-
|
|
259
|
+
if (isJson()) {
|
|
260
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient USDC. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
console.error(chalk.red(` Insufficient USDC. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
264
|
+
}
|
|
245
265
|
process.exit(1);
|
|
246
266
|
}
|
|
247
267
|
try {
|
|
@@ -306,12 +326,22 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
306
326
|
const amountRaw = ethers.parseUnits(amount, 6);
|
|
307
327
|
const ethBal = await provider.getBalance(wallet.address);
|
|
308
328
|
if (ethBal < ethers.parseEther("0.003")) {
|
|
309
|
-
|
|
329
|
+
if (isJson()) {
|
|
330
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", "Insufficient ETH on Ethereum for gas. Need ~0.003 ETH ($3+)."));
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
console.error(chalk.red(" Insufficient ETH on Ethereum for gas. Need ~0.003 ETH ($3+)."));
|
|
334
|
+
}
|
|
310
335
|
process.exit(1);
|
|
311
336
|
}
|
|
312
337
|
const usdcBal = await usdc.balanceOf(wallet.address);
|
|
313
338
|
if (usdcBal < amountRaw) {
|
|
314
|
-
|
|
339
|
+
if (isJson()) {
|
|
340
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient USDC on Ethereum. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
console.error(chalk.red(` Insufficient USDC on Ethereum. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
344
|
+
}
|
|
315
345
|
process.exit(1);
|
|
316
346
|
}
|
|
317
347
|
const allowance = await usdc.allowance(wallet.address, LIGHTER_CONTRACT);
|
|
@@ -399,7 +429,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
399
429
|
console.log(` Intent address: ${intentAddress}`);
|
|
400
430
|
const gasBal = await provider.getBalance(wallet.address);
|
|
401
431
|
if (gasBal < ethers.parseEther("0.00005")) {
|
|
402
|
-
|
|
432
|
+
if (isJson()) {
|
|
433
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient gas token on ${chainInfo.name}. Need native token for gas (~$0.01).`));
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
console.error(chalk.red(` Insufficient gas token on ${chainInfo.name}. Need native token for gas (~$0.01).`));
|
|
437
|
+
}
|
|
403
438
|
process.exit(1);
|
|
404
439
|
}
|
|
405
440
|
const usdc = new ethers.Contract(chainInfo.usdc, [
|
|
@@ -409,7 +444,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
409
444
|
const amountRaw = ethers.parseUnits(amount, 6);
|
|
410
445
|
const usdcBal = await usdc.balanceOf(wallet.address);
|
|
411
446
|
if (usdcBal < amountRaw) {
|
|
412
|
-
|
|
447
|
+
if (isJson()) {
|
|
448
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient USDC on ${chainInfo.name}. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
console.error(chalk.red(` Insufficient USDC on ${chainInfo.name}. Have: $${formatUsd(Number(ethers.formatUnits(usdcBal, 6)))}`));
|
|
452
|
+
}
|
|
413
453
|
process.exit(1);
|
|
414
454
|
}
|
|
415
455
|
if (!isJson())
|
|
@@ -534,7 +574,12 @@ export function registerFundsCommands(program, getAdapter, isJson, getNetwork) {
|
|
|
534
574
|
const balance = await adapter.getBalance();
|
|
535
575
|
const available = Number(balance.available);
|
|
536
576
|
if (amountNum > available) {
|
|
537
|
-
|
|
577
|
+
if (isJson()) {
|
|
578
|
+
printJson(jsonError("INSUFFICIENT_BALANCE", `Insufficient withdrawable balance. Available: $${formatUsd(available)}`));
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
console.error(chalk.red(` Insufficient withdrawable balance. Available: $${formatUsd(available)}`));
|
|
582
|
+
}
|
|
538
583
|
process.exit(1);
|
|
539
584
|
}
|
|
540
585
|
try {
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ declare function loadEnvFile(): Record<string, string>;
|
|
|
5
5
|
declare function setEnvVar(key: string, value: string): void;
|
|
6
6
|
export declare const EXCHANGE_ENV_MAP: Record<string, {
|
|
7
7
|
envKey: string;
|
|
8
|
+
envKeySecret?: string;
|
|
8
9
|
chain: "solana" | "evm" | "apikey";
|
|
9
10
|
label: string;
|
|
10
11
|
}>;
|
package/dist/commands/init.js
CHANGED
|
@@ -70,7 +70,7 @@ export const EXCHANGE_ENV_MAP = {
|
|
|
70
70
|
pacifica: { envKey: "PACIFICA_PRIVATE_KEY", chain: "solana", label: "Pacifica (Solana)" },
|
|
71
71
|
hyperliquid: { envKey: "HL_PRIVATE_KEY", chain: "evm", label: "Hyperliquid (EVM)" },
|
|
72
72
|
lighter: { envKey: "LIGHTER_PRIVATE_KEY", chain: "evm", label: "Lighter (EVM)" },
|
|
73
|
-
aster: { envKey: "ASTER_API_KEY", chain: "apikey", label: "Aster (BNB Chain)" },
|
|
73
|
+
aster: { envKey: "ASTER_API_KEY", envKeySecret: "ASTER_API_SECRET", chain: "apikey", label: "Aster (BNB Chain)" },
|
|
74
74
|
};
|
|
75
75
|
// ── Validate keys ─────────────────────────────────────────────
|
|
76
76
|
export async function validateKey(chain, key) {
|
|
@@ -146,8 +146,9 @@ export function registerInitCommand(program) {
|
|
|
146
146
|
console.log(` 1) ${chalk.cyan("Pacifica")} ${chalk.gray("— Solana perps (USDC on Solana)")}`);
|
|
147
147
|
console.log(` 2) ${chalk.cyan("Hyperliquid")} ${chalk.gray("— EVM perps (USDC on Arbitrum)")}`);
|
|
148
148
|
console.log(` 3) ${chalk.cyan("Lighter")} ${chalk.gray("— EVM perps (USDC on Ethereum/Arb)")}`);
|
|
149
|
+
console.log(` 4) ${chalk.cyan("Aster")} ${chalk.gray("— BNB Chain perps (API key + secret)")}`);
|
|
149
150
|
console.log();
|
|
150
|
-
const exchangeChoice = await ask(rl, " Which exchange(s)? (1,2,3 or 'all'): ");
|
|
151
|
+
const exchangeChoice = await ask(rl, " Which exchange(s)? (1,2,3,4 or 'all'): ");
|
|
151
152
|
const selected = parseExchangeChoice(exchangeChoice);
|
|
152
153
|
if (selected.length === 0) {
|
|
153
154
|
console.log(chalk.red("\n No exchanges selected.\n"));
|
|
@@ -158,6 +159,7 @@ export function registerInitCommand(program) {
|
|
|
158
159
|
// EVM exchanges can share the same key
|
|
159
160
|
const evmExchanges = selected.filter((e) => EXCHANGE_ENV_MAP[e].chain === "evm");
|
|
160
161
|
const solExchanges = selected.filter((e) => EXCHANGE_ENV_MAP[e].chain === "solana");
|
|
162
|
+
const apikeyExchanges = selected.filter((e) => EXCHANGE_ENV_MAP[e].chain === "apikey");
|
|
161
163
|
const newEnv = { ...env };
|
|
162
164
|
if (evmExchanges.length > 0) {
|
|
163
165
|
console.log(chalk.cyan.bold("\n EVM Private Key") + chalk.gray(` (for ${evmExchanges.join(", ")})`));
|
|
@@ -213,6 +215,34 @@ export function registerInitCommand(program) {
|
|
|
213
215
|
}
|
|
214
216
|
}
|
|
215
217
|
}
|
|
218
|
+
if (apikeyExchanges.length > 0) {
|
|
219
|
+
for (const ex of apikeyExchanges) {
|
|
220
|
+
const info = EXCHANGE_ENV_MAP[ex];
|
|
221
|
+
console.log(chalk.cyan.bold(`\n ${info.label} API Credentials`));
|
|
222
|
+
const apiKey = await ask(rl, ` ${info.label} API key: `);
|
|
223
|
+
if (!apiKey) {
|
|
224
|
+
console.log(chalk.gray(" Skipped."));
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const { valid, address } = await validateKey("apikey", apiKey);
|
|
228
|
+
if (!valid) {
|
|
229
|
+
console.log(chalk.red(" Invalid API key (must be at least 16 chars), skipped."));
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
newEnv[info.envKey] = apiKey;
|
|
233
|
+
console.log(` ${chalk.green("OK")} ${chalk.gray(address)}`);
|
|
234
|
+
if (info.envKeySecret) {
|
|
235
|
+
const secret = await ask(rl, ` ${info.label} API secret: `);
|
|
236
|
+
if (secret) {
|
|
237
|
+
newEnv[info.envKeySecret] = secret;
|
|
238
|
+
console.log(` ${chalk.green("OK")} secret saved`);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
console.log(chalk.yellow(" No secret provided — some operations may fail."));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
216
246
|
// Default exchange
|
|
217
247
|
const settings = loadSettings();
|
|
218
248
|
if (selected.length === 1) {
|
|
@@ -256,7 +286,9 @@ export function registerInitCommand(program) {
|
|
|
256
286
|
}
|
|
257
287
|
function parseExchangeChoice(input) {
|
|
258
288
|
const lower = input.toLowerCase().trim();
|
|
259
|
-
if (lower === "all" || lower === "1,2,3")
|
|
289
|
+
if (lower === "all" || lower === "1,2,3,4")
|
|
290
|
+
return ["pacifica", "hyperliquid", "lighter", "aster"];
|
|
291
|
+
if (lower === "1,2,3")
|
|
260
292
|
return ["pacifica", "hyperliquid", "lighter"];
|
|
261
293
|
const exchanges = [];
|
|
262
294
|
const parts = lower.split(/[,\s]+/);
|
|
@@ -267,6 +299,8 @@ function parseExchangeChoice(input) {
|
|
|
267
299
|
exchanges.push("hyperliquid");
|
|
268
300
|
else if (p === "3" || p.startsWith("lig") || p === "lt")
|
|
269
301
|
exchanges.push("lighter");
|
|
302
|
+
else if (p === "4" || p.startsWith("ast"))
|
|
303
|
+
exchanges.push("aster");
|
|
270
304
|
}
|
|
271
305
|
return [...new Set(exchanges)];
|
|
272
306
|
}
|
package/dist/commands/manage.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { printJson, jsonOk } from "../utils.js";
|
|
1
|
+
import { printJson, jsonOk, jsonError } from "../utils.js";
|
|
2
2
|
import { setEnvVar } from "./init.js";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { hasPacificaSdk, hasLighterAccount } from "../exchanges/capabilities.js";
|
|
@@ -19,6 +19,10 @@ export function registerManageCommands(program, getAdapter, isJson, getPacificaA
|
|
|
19
19
|
.action(async (symbol, mode) => {
|
|
20
20
|
const m = mode.toLowerCase();
|
|
21
21
|
if (m !== "cross" && m !== "isolated") {
|
|
22
|
+
if (isJson()) {
|
|
23
|
+
console.error(JSON.stringify(jsonError("INVALID_PARAMS", "Mode must be cross or isolated")));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
22
26
|
console.error(chalk.red("Mode must be cross or isolated"));
|
|
23
27
|
process.exit(1);
|
|
24
28
|
}
|
package/dist/config.js
CHANGED
|
@@ -51,7 +51,7 @@ export async function loadPrivateKey(exchange, pkOverride, walletName) {
|
|
|
51
51
|
catch {
|
|
52
52
|
// wallet module not available, skip
|
|
53
53
|
}
|
|
54
|
-
//
|
|
54
|
+
// 6. Legacy key file (~/.perp/<exchange>.key)
|
|
55
55
|
const keyFile = resolve(process.env.HOME || "~", ".perp", `${exchange}.key`);
|
|
56
56
|
if (existsSync(keyFile)) {
|
|
57
57
|
return readFileSync(keyFile, "utf-8").trim();
|
|
@@ -12,7 +12,7 @@ export declare const TESTNET_PACIFICA_VAULT = "5SDFdHZGTZbyRYu54CgmRkCGnPHC5pYaN
|
|
|
12
12
|
export declare const TESTNET_USDC_MINT = "USDPqRbLidFGufty2s3oizmDEKdqx7ePTqzDMbf5ZKM";
|
|
13
13
|
export declare const DEFAULT_EXPIRY_WINDOW = 5000;
|
|
14
14
|
export declare const USDC_DECIMALS = 6;
|
|
15
|
-
export declare const BUILDER_CODE
|
|
15
|
+
export declare const BUILDER_CODE = "PERPCLI";
|
|
16
16
|
export type Network = "mainnet" | "testnet";
|
|
17
17
|
export declare function getNetworkConfig(network?: Network): {
|
|
18
18
|
restUrl: string;
|
|
@@ -20,7 +20,10 @@ export const DEFAULT_EXPIRY_WINDOW = 5000; // 5 seconds
|
|
|
20
20
|
// USDC decimals
|
|
21
21
|
export const USDC_DECIMALS = 6;
|
|
22
22
|
// Builder code — 0% fee, used for Pacifica hackathon tracking
|
|
23
|
-
|
|
23
|
+
// The actual 3-way fallback (env → settings.referralCodes.pacifica → "PERPCLI") is
|
|
24
|
+
// resolved in index.ts before constructing PacificaAdapter. This constant is only
|
|
25
|
+
// a last-resort default for direct PacificaClient usage without a builderCode arg.
|
|
26
|
+
export const BUILDER_CODE = "PERPCLI";
|
|
24
27
|
export function getNetworkConfig(network = "mainnet") {
|
|
25
28
|
if (network === "testnet") {
|
|
26
29
|
return {
|