@hypurrquant/defi-cli 0.2.3 → 0.2.4

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/main.js CHANGED
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/main.ts
4
+ import { config } from "dotenv";
5
+ import { resolve as resolve4 } from "path";
6
+
3
7
  // src/cli.ts
4
8
  import { Command } from "commander";
5
9
  import { createRequire } from "module";
@@ -8223,6 +8227,150 @@ function registerFarm(parent, getOpts, makeExecutor2) {
8223
8227
  });
8224
8228
  }
8225
8229
 
8230
+ // src/commands/setup.ts
8231
+ import pc2 from "picocolors";
8232
+ import { createInterface } from "readline";
8233
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
8234
+ import { resolve as resolve3 } from "path";
8235
+ var DEFI_DIR = resolve3(process.env.HOME || "~", ".defi");
8236
+ var ENV_FILE = resolve3(DEFI_DIR, ".env");
8237
+ function ensureDefiDir() {
8238
+ if (!existsSync3(DEFI_DIR)) mkdirSync2(DEFI_DIR, { recursive: true, mode: 448 });
8239
+ }
8240
+ function loadEnvFile() {
8241
+ if (!existsSync3(ENV_FILE)) return {};
8242
+ const lines = readFileSync3(ENV_FILE, "utf-8").split("\n");
8243
+ const env = {};
8244
+ for (const line of lines) {
8245
+ const trimmed = line.trim();
8246
+ if (!trimmed || trimmed.startsWith("#")) continue;
8247
+ const eqIdx = trimmed.indexOf("=");
8248
+ if (eqIdx > 0) {
8249
+ env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
8250
+ }
8251
+ }
8252
+ return env;
8253
+ }
8254
+ function writeEnvFile(env) {
8255
+ ensureDefiDir();
8256
+ const lines = [
8257
+ "# defi-cli configuration",
8258
+ "# Generated by 'defi setup' \u2014 edit freely",
8259
+ ""
8260
+ ];
8261
+ for (const [key, value] of Object.entries(env)) {
8262
+ lines.push(`${key}=${value}`);
8263
+ }
8264
+ lines.push("");
8265
+ writeFileSync2(ENV_FILE, lines.join("\n"), { mode: 384 });
8266
+ }
8267
+ function ask(rl, question) {
8268
+ return new Promise((res) => rl.question(question, (answer) => res(answer.trim())));
8269
+ }
8270
+ function isValidAddress(s) {
8271
+ return /^0x[0-9a-fA-F]{40}$/.test(s);
8272
+ }
8273
+ function isValidPrivateKey(s) {
8274
+ return /^0x[0-9a-fA-F]{64}$/.test(s);
8275
+ }
8276
+ async function deriveAddress(privateKey) {
8277
+ try {
8278
+ const { privateKeyToAccount: privateKeyToAccount3 } = await import("viem/accounts");
8279
+ const account = privateKeyToAccount3(privateKey);
8280
+ return account.address;
8281
+ } catch {
8282
+ return null;
8283
+ }
8284
+ }
8285
+ function registerSetup(program2) {
8286
+ program2.command("setup").alias("init").description("Interactive setup wizard \u2014 configure wallet & RPC URLs").action(async () => {
8287
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
8288
+ try {
8289
+ console.log(pc2.cyan(pc2.bold("\n defi-cli Setup Wizard\n")));
8290
+ const existing = loadEnvFile();
8291
+ if (Object.keys(existing).length > 0) {
8292
+ console.log(pc2.white(" Current configuration:"));
8293
+ for (const [key, value] of Object.entries(existing)) {
8294
+ const masked = key.toLowerCase().includes("key") ? value.slice(0, 6) + "..." + value.slice(-4) : value;
8295
+ console.log(` ${pc2.cyan(key.padEnd(24))} ${pc2.gray(masked)}`);
8296
+ }
8297
+ console.log();
8298
+ const overwrite = await ask(rl, " Overwrite existing config? (y/N): ");
8299
+ if (overwrite.toLowerCase() !== "y" && overwrite.toLowerCase() !== "yes") {
8300
+ console.log(pc2.gray("\n Keeping existing configuration.\n"));
8301
+ rl.close();
8302
+ return;
8303
+ }
8304
+ console.log();
8305
+ }
8306
+ const newEnv = {};
8307
+ console.log(pc2.cyan(pc2.bold(" Wallet")));
8308
+ const privateKey = await ask(rl, " Private key (optional, for --broadcast, 0x...): ");
8309
+ if (privateKey) {
8310
+ const normalized = privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
8311
+ if (!isValidPrivateKey(normalized)) {
8312
+ console.log(pc2.red(" Invalid private key (must be 0x + 64 hex chars). Skipped."));
8313
+ } else {
8314
+ newEnv.DEFI_PRIVATE_KEY = normalized;
8315
+ const derived = await deriveAddress(normalized);
8316
+ if (derived) {
8317
+ newEnv.DEFI_WALLET_ADDRESS = derived;
8318
+ console.log(` ${pc2.green("OK")} derived address: ${pc2.gray(derived)}`);
8319
+ }
8320
+ }
8321
+ }
8322
+ if (!newEnv.DEFI_WALLET_ADDRESS) {
8323
+ const address = await ask(rl, " Wallet address (0x...): ");
8324
+ if (address) {
8325
+ if (!isValidAddress(address)) {
8326
+ console.log(pc2.yellow(" Invalid address format. Skipping."));
8327
+ } else {
8328
+ newEnv.DEFI_WALLET_ADDRESS = address;
8329
+ console.log(` ${pc2.green("OK")} ${pc2.gray(address)}`);
8330
+ }
8331
+ }
8332
+ }
8333
+ console.log(pc2.cyan(pc2.bold("\n RPC URLs")) + pc2.gray(" (press Enter to use public defaults)"));
8334
+ const hyperevmRpc = await ask(rl, " HyperEVM RPC URL: ");
8335
+ if (hyperevmRpc) {
8336
+ newEnv.HYPEREVM_RPC_URL = hyperevmRpc;
8337
+ console.log(` ${pc2.green("OK")} HyperEVM RPC set`);
8338
+ }
8339
+ const mantleRpc = await ask(rl, " Mantle RPC URL: ");
8340
+ if (mantleRpc) {
8341
+ newEnv.MANTLE_RPC_URL = mantleRpc;
8342
+ console.log(` ${pc2.green("OK")} Mantle RPC set`);
8343
+ }
8344
+ const finalEnv = { ...existing, ...newEnv };
8345
+ writeEnvFile(finalEnv);
8346
+ console.log(pc2.cyan(pc2.bold("\n Setup Complete!\n")));
8347
+ console.log(` Config: ${pc2.gray(ENV_FILE)}`);
8348
+ if (finalEnv.DEFI_WALLET_ADDRESS) {
8349
+ console.log(` Wallet: ${pc2.gray(finalEnv.DEFI_WALLET_ADDRESS)}`);
8350
+ }
8351
+ if (finalEnv.DEFI_PRIVATE_KEY) {
8352
+ console.log(` Key: ${pc2.green("configured")}`);
8353
+ }
8354
+ if (finalEnv.HYPEREVM_RPC_URL) {
8355
+ console.log(` HyperEVM RPC: ${pc2.gray(finalEnv.HYPEREVM_RPC_URL)}`);
8356
+ }
8357
+ if (finalEnv.MANTLE_RPC_URL) {
8358
+ console.log(` Mantle RPC: ${pc2.gray(finalEnv.MANTLE_RPC_URL)}`);
8359
+ }
8360
+ console.log(pc2.bold(pc2.white("\n Next steps:")));
8361
+ console.log(` ${pc2.green("defi portfolio")} view balances & positions`);
8362
+ console.log(` ${pc2.green("defi scan")} scan for exploits`);
8363
+ console.log(` ${pc2.green("defi dex quote")} get a swap quote`);
8364
+ console.log(` ${pc2.green("defi --help")} browse all commands
8365
+ `);
8366
+ rl.close();
8367
+ } catch (err) {
8368
+ rl.close();
8369
+ throw err;
8370
+ }
8371
+ });
8372
+ }
8373
+
8226
8374
  // src/cli.ts
8227
8375
  var _require = createRequire(import.meta.url);
8228
8376
  var _pkg = _require("../package.json");
@@ -8274,6 +8422,7 @@ registerSwap(program, getOutputMode, makeExecutor);
8274
8422
  registerBridge(program, getOutputMode);
8275
8423
  registerNft(program, getOutputMode);
8276
8424
  registerFarm(program, getOutputMode, makeExecutor);
8425
+ registerSetup(program);
8277
8426
  program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
8278
8427
  const executor = makeExecutor();
8279
8428
  process.stderr.write("Agent mode: reading JSON commands from stdin...\n");
@@ -8282,7 +8431,7 @@ program.command("agent").description("Agent mode: read JSON commands from stdin
8282
8431
  });
8283
8432
 
8284
8433
  // src/landing.ts
8285
- import pc2 from "picocolors";
8434
+ import pc3 from "picocolors";
8286
8435
  import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31, formatUnits } from "viem";
8287
8436
  var HYPEREVM_DISPLAY = ["HYPE", "WHYPE", "USDC", "USDT0", "USDe", "kHYPE", "wstHYPE"];
8288
8437
  var MANTLE_DISPLAY = ["MNT", "WMNT", "USDC", "USDT", "WETH", "mETH"];
@@ -8376,20 +8525,20 @@ async function showLandingPage(isJson) {
8376
8525
  const version = pkg.version;
8377
8526
  if (!wallet) {
8378
8527
  console.log("");
8379
- console.log(pc2.bold(pc2.cyan(" DeFi CLI v" + version)));
8528
+ console.log(pc3.bold(pc3.cyan(" DeFi CLI v" + version)));
8380
8529
  console.log("");
8381
- console.log(pc2.yellow(" Wallet not configured."));
8530
+ console.log(pc3.yellow(" Wallet not configured."));
8382
8531
  console.log(" Set DEFI_WALLET_ADDRESS to see your balances:");
8383
8532
  console.log("");
8384
- console.log(pc2.dim(" export DEFI_WALLET_ADDRESS=0x..."));
8533
+ console.log(pc3.dim(" export DEFI_WALLET_ADDRESS=0x..."));
8385
8534
  console.log("");
8386
8535
  console.log(" Commands:");
8387
- console.log(pc2.dim(" defi status Protocol overview"));
8388
- console.log(pc2.dim(" defi lending rates Compare lending APYs"));
8389
- console.log(pc2.dim(" defi dex quote Get swap quotes"));
8390
- console.log(pc2.dim(" defi portfolio View all positions"));
8391
- console.log(pc2.dim(" defi scan Exploit detection"));
8392
- console.log(pc2.dim(" defi --help Full command list"));
8536
+ console.log(pc3.dim(" defi status Protocol overview"));
8537
+ console.log(pc3.dim(" defi lending rates Compare lending APYs"));
8538
+ console.log(pc3.dim(" defi dex quote Get swap quotes"));
8539
+ console.log(pc3.dim(" defi portfolio View all positions"));
8540
+ console.log(pc3.dim(" defi scan Exploit detection"));
8541
+ console.log(pc3.dim(" defi --help Full command list"));
8393
8542
  console.log("");
8394
8543
  return;
8395
8544
  }
@@ -8411,20 +8560,20 @@ async function showLandingPage(isJson) {
8411
8560
  const divider = "\u2500".repeat(colWidth - 2);
8412
8561
  console.log("");
8413
8562
  console.log(
8414
- pc2.bold(pc2.cyan(" DeFi CLI v" + version)) + pc2.dim(" \u2014 ") + pc2.bold(heChain.name) + pc2.dim(" \xB7 ") + pc2.bold(mantleChain.name)
8563
+ pc3.bold(pc3.cyan(" DeFi CLI v" + version)) + pc3.dim(" \u2014 ") + pc3.bold(heChain.name) + pc3.dim(" \xB7 ") + pc3.bold(mantleChain.name)
8415
8564
  );
8416
8565
  console.log("");
8417
- console.log(" Wallet: " + pc2.yellow(shortenAddress(wallet)));
8566
+ console.log(" Wallet: " + pc3.yellow(shortenAddress(wallet)));
8418
8567
  console.log("");
8419
8568
  const heHeader = padRight(
8420
- " " + pc2.bold(heChain.name),
8569
+ " " + pc3.bold(heChain.name),
8421
8570
  colWidth + 10
8422
8571
  /* account for ANSI */
8423
8572
  );
8424
- const mantleHeader = pc2.bold(mantleChain.name);
8573
+ const mantleHeader = pc3.bold(mantleChain.name);
8425
8574
  console.log(heHeader + " " + mantleHeader);
8426
- const heDivider = padRight(" " + pc2.dim(divider), colWidth + 10);
8427
- const mantleDivider = pc2.dim(divider);
8575
+ const heDivider = padRight(" " + pc3.dim(divider), colWidth + 10);
8576
+ const mantleDivider = pc3.dim(divider);
8428
8577
  console.log(heDivider + " " + mantleDivider);
8429
8578
  const maxRows = Math.max(heBalances.length, mantleBalances.length);
8430
8579
  for (let i = 0; i < maxRows; i++) {
@@ -8432,25 +8581,27 @@ async function showLandingPage(isJson) {
8432
8581
  const mantleEntry = mantleBalances[i];
8433
8582
  const heText = heEntry ? formatBalanceLine(heEntry.symbol, heEntry.balance) : "";
8434
8583
  const mantleText = mantleEntry ? formatBalanceLine(mantleEntry.symbol, mantleEntry.balance) : "";
8435
- const heColored = heEntry ? heEntry.balance === "0.00" || heEntry.balance === "?" ? pc2.dim(heText) : heText : "";
8436
- const mantleColored = mantleEntry ? mantleEntry.balance === "0.00" || mantleEntry.balance === "?" ? pc2.dim(mantleText) : mantleText : "";
8584
+ const heColored = heEntry ? heEntry.balance === "0.00" || heEntry.balance === "?" ? pc3.dim(heText) : heText : "";
8585
+ const mantleColored = mantleEntry ? mantleEntry.balance === "0.00" || mantleEntry.balance === "?" ? pc3.dim(mantleText) : mantleText : "";
8437
8586
  const visibleLen = heText.length;
8438
8587
  const padNeeded = colWidth - visibleLen;
8439
8588
  const paddedHe = heColored + (padNeeded > 0 ? " ".repeat(padNeeded) : "");
8440
8589
  console.log(paddedHe + " " + mantleColored);
8441
8590
  }
8442
8591
  console.log("");
8443
- console.log(" " + pc2.bold("Commands:"));
8444
- console.log(" " + pc2.cyan("defi status") + " Protocol overview");
8445
- console.log(" " + pc2.cyan("defi lending rates") + " Compare lending APYs");
8446
- console.log(" " + pc2.cyan("defi dex quote") + " Get swap quotes");
8447
- console.log(" " + pc2.cyan("defi portfolio") + " View all positions");
8448
- console.log(" " + pc2.cyan("defi scan") + " Exploit detection");
8449
- console.log(" " + pc2.cyan("defi --help") + " Full command list");
8592
+ console.log(" " + pc3.bold("Commands:"));
8593
+ console.log(" " + pc3.cyan("defi status") + " Protocol overview");
8594
+ console.log(" " + pc3.cyan("defi lending rates") + " Compare lending APYs");
8595
+ console.log(" " + pc3.cyan("defi dex quote") + " Get swap quotes");
8596
+ console.log(" " + pc3.cyan("defi portfolio") + " View all positions");
8597
+ console.log(" " + pc3.cyan("defi scan") + " Exploit detection");
8598
+ console.log(" " + pc3.cyan("defi --help") + " Full command list");
8450
8599
  console.log("");
8451
8600
  }
8452
8601
 
8453
8602
  // src/main.ts
8603
+ config({ path: resolve4(process.env.HOME || "~", ".defi", ".env"), quiet: true });
8604
+ config({ quiet: true });
8454
8605
  async function main() {
8455
8606
  try {
8456
8607
  const rawArgs = process.argv.slice(2);
@@ -8479,7 +8630,9 @@ async function main() {
8479
8630
  "bridge",
8480
8631
  "nft",
8481
8632
  "farm",
8482
- "agent"
8633
+ "agent",
8634
+ "setup",
8635
+ "init"
8483
8636
  ]);
8484
8637
  const hasSubcommand = rawArgs.some((a) => !a.startsWith("-") && knownSubcommands.has(a));
8485
8638
  const isJson = rawArgs.includes("--json") || rawArgs.includes("--ndjson");