@hypurrquant/defi-cli 0.2.2 → 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,7 +1,12 @@
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";
9
+ import { createRequire } from "module";
5
10
 
6
11
  // src/executor.ts
7
12
  import { createPublicClient as createPublicClient2, createWalletClient, http as http2 } from "viem";
@@ -8222,7 +8227,153 @@ function registerFarm(parent, getOpts, makeExecutor2) {
8222
8227
  });
8223
8228
  }
8224
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
+
8225
8374
  // src/cli.ts
8375
+ var _require = createRequire(import.meta.url);
8376
+ var _pkg = _require("../package.json");
8226
8377
  var BANNER = `
8227
8378
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
8228
8379
  \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
@@ -8236,7 +8387,7 @@ var BANNER = `
8236
8387
  Scan exploits, swap tokens, bridge assets, track whales,
8237
8388
  compare yields \u2014 all from your terminal.
8238
8389
  `;
8239
- var program = new Command().name("defi").description("DeFi CLI \u2014 Multi-chain DeFi toolkit").version("0.1.0").addHelpText("before", BANNER).option("--json", "Output as JSON").option("--ndjson", "Output as newline-delimited JSON").option("--fields <fields>", "Select specific output fields (comma-separated)").option("--chain <chain>", "Target chain", "hyperevm").option("--dry-run", "Dry-run mode (default, no broadcast)", true).option("--broadcast", "Actually broadcast the transaction");
8390
+ var program = new Command().name("defi").description("DeFi CLI \u2014 Multi-chain DeFi toolkit").version(_pkg.version).addHelpText("before", BANNER).option("--json", "Output as JSON").option("--ndjson", "Output as newline-delimited JSON").option("--fields <fields>", "Select specific output fields (comma-separated)").option("--chain <chain>", "Target chain", "hyperevm").option("--dry-run", "Dry-run mode (default, no broadcast)", true).option("--broadcast", "Actually broadcast the transaction");
8240
8391
  function getOutputMode() {
8241
8392
  const opts = program.opts();
8242
8393
  return parseOutputMode(opts);
@@ -8271,6 +8422,7 @@ registerSwap(program, getOutputMode, makeExecutor);
8271
8422
  registerBridge(program, getOutputMode);
8272
8423
  registerNft(program, getOutputMode);
8273
8424
  registerFarm(program, getOutputMode, makeExecutor);
8425
+ registerSetup(program);
8274
8426
  program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
8275
8427
  const executor = makeExecutor();
8276
8428
  process.stderr.write("Agent mode: reading JSON commands from stdin...\n");
@@ -8279,7 +8431,7 @@ program.command("agent").description("Agent mode: read JSON commands from stdin
8279
8431
  });
8280
8432
 
8281
8433
  // src/landing.ts
8282
- import pc2 from "picocolors";
8434
+ import pc3 from "picocolors";
8283
8435
  import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31, formatUnits } from "viem";
8284
8436
  var HYPEREVM_DISPLAY = ["HYPE", "WHYPE", "USDC", "USDT0", "USDe", "kHYPE", "wstHYPE"];
8285
8437
  var MANTLE_DISPLAY = ["MNT", "WMNT", "USDC", "USDT", "WETH", "mETH"];
@@ -8367,23 +8519,26 @@ async function showLandingPage(isJson) {
8367
8519
  }, null, 2));
8368
8520
  return;
8369
8521
  }
8370
- const version = "0.2.0";
8522
+ const { createRequire: createRequire2 } = await import("module");
8523
+ const _require2 = createRequire2(import.meta.url);
8524
+ const pkg = _require2("../package.json");
8525
+ const version = pkg.version;
8371
8526
  if (!wallet) {
8372
8527
  console.log("");
8373
- console.log(pc2.bold(pc2.cyan(" DeFi CLI v" + version)));
8528
+ console.log(pc3.bold(pc3.cyan(" DeFi CLI v" + version)));
8374
8529
  console.log("");
8375
- console.log(pc2.yellow(" Wallet not configured."));
8530
+ console.log(pc3.yellow(" Wallet not configured."));
8376
8531
  console.log(" Set DEFI_WALLET_ADDRESS to see your balances:");
8377
8532
  console.log("");
8378
- console.log(pc2.dim(" export DEFI_WALLET_ADDRESS=0x..."));
8533
+ console.log(pc3.dim(" export DEFI_WALLET_ADDRESS=0x..."));
8379
8534
  console.log("");
8380
8535
  console.log(" Commands:");
8381
- console.log(pc2.dim(" defi status Protocol overview"));
8382
- console.log(pc2.dim(" defi lending rates Compare lending APYs"));
8383
- console.log(pc2.dim(" defi dex quote Get swap quotes"));
8384
- console.log(pc2.dim(" defi portfolio View all positions"));
8385
- console.log(pc2.dim(" defi scan Exploit detection"));
8386
- 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"));
8387
8542
  console.log("");
8388
8543
  return;
8389
8544
  }
@@ -8405,20 +8560,20 @@ async function showLandingPage(isJson) {
8405
8560
  const divider = "\u2500".repeat(colWidth - 2);
8406
8561
  console.log("");
8407
8562
  console.log(
8408
- 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)
8409
8564
  );
8410
8565
  console.log("");
8411
- console.log(" Wallet: " + pc2.yellow(shortenAddress(wallet)));
8566
+ console.log(" Wallet: " + pc3.yellow(shortenAddress(wallet)));
8412
8567
  console.log("");
8413
8568
  const heHeader = padRight(
8414
- " " + pc2.bold(heChain.name),
8569
+ " " + pc3.bold(heChain.name),
8415
8570
  colWidth + 10
8416
8571
  /* account for ANSI */
8417
8572
  );
8418
- const mantleHeader = pc2.bold(mantleChain.name);
8573
+ const mantleHeader = pc3.bold(mantleChain.name);
8419
8574
  console.log(heHeader + " " + mantleHeader);
8420
- const heDivider = padRight(" " + pc2.dim(divider), colWidth + 10);
8421
- const mantleDivider = pc2.dim(divider);
8575
+ const heDivider = padRight(" " + pc3.dim(divider), colWidth + 10);
8576
+ const mantleDivider = pc3.dim(divider);
8422
8577
  console.log(heDivider + " " + mantleDivider);
8423
8578
  const maxRows = Math.max(heBalances.length, mantleBalances.length);
8424
8579
  for (let i = 0; i < maxRows; i++) {
@@ -8426,25 +8581,27 @@ async function showLandingPage(isJson) {
8426
8581
  const mantleEntry = mantleBalances[i];
8427
8582
  const heText = heEntry ? formatBalanceLine(heEntry.symbol, heEntry.balance) : "";
8428
8583
  const mantleText = mantleEntry ? formatBalanceLine(mantleEntry.symbol, mantleEntry.balance) : "";
8429
- const heColored = heEntry ? heEntry.balance === "0.00" || heEntry.balance === "?" ? pc2.dim(heText) : heText : "";
8430
- 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 : "";
8431
8586
  const visibleLen = heText.length;
8432
8587
  const padNeeded = colWidth - visibleLen;
8433
8588
  const paddedHe = heColored + (padNeeded > 0 ? " ".repeat(padNeeded) : "");
8434
8589
  console.log(paddedHe + " " + mantleColored);
8435
8590
  }
8436
8591
  console.log("");
8437
- console.log(" " + pc2.bold("Commands:"));
8438
- console.log(" " + pc2.cyan("defi status") + " Protocol overview");
8439
- console.log(" " + pc2.cyan("defi lending rates") + " Compare lending APYs");
8440
- console.log(" " + pc2.cyan("defi dex quote") + " Get swap quotes");
8441
- console.log(" " + pc2.cyan("defi portfolio") + " View all positions");
8442
- console.log(" " + pc2.cyan("defi scan") + " Exploit detection");
8443
- 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");
8444
8599
  console.log("");
8445
8600
  }
8446
8601
 
8447
8602
  // src/main.ts
8603
+ config({ path: resolve4(process.env.HOME || "~", ".defi", ".env"), quiet: true });
8604
+ config({ quiet: true });
8448
8605
  async function main() {
8449
8606
  try {
8450
8607
  const rawArgs = process.argv.slice(2);
@@ -8473,12 +8630,15 @@ async function main() {
8473
8630
  "bridge",
8474
8631
  "nft",
8475
8632
  "farm",
8476
- "agent"
8633
+ "agent",
8634
+ "setup",
8635
+ "init"
8477
8636
  ]);
8478
8637
  const hasSubcommand = rawArgs.some((a) => !a.startsWith("-") && knownSubcommands.has(a));
8479
8638
  const isJson = rawArgs.includes("--json") || rawArgs.includes("--ndjson");
8480
8639
  const isHelp = rawArgs.includes("--help") || rawArgs.includes("-h");
8481
- if (!isHelp && (rawArgs.length === 0 || !hasSubcommand)) {
8640
+ const isVersion = rawArgs.includes("--version") || rawArgs.includes("-V");
8641
+ if (!isHelp && !isVersion && (rawArgs.length === 0 || !hasSubcommand)) {
8482
8642
  await showLandingPage(isJson);
8483
8643
  return;
8484
8644
  }