@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/index.js +149 -1
- package/dist/index.js.map +1 -1
- package/dist/main.js +189 -29
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
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(
|
|
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
|
|
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
|
|
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(
|
|
8528
|
+
console.log(pc3.bold(pc3.cyan(" DeFi CLI v" + version)));
|
|
8374
8529
|
console.log("");
|
|
8375
|
-
console.log(
|
|
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(
|
|
8533
|
+
console.log(pc3.dim(" export DEFI_WALLET_ADDRESS=0x..."));
|
|
8379
8534
|
console.log("");
|
|
8380
8535
|
console.log(" Commands:");
|
|
8381
|
-
console.log(
|
|
8382
|
-
console.log(
|
|
8383
|
-
console.log(
|
|
8384
|
-
console.log(
|
|
8385
|
-
console.log(
|
|
8386
|
-
console.log(
|
|
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
|
-
|
|
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: " +
|
|
8566
|
+
console.log(" Wallet: " + pc3.yellow(shortenAddress(wallet)));
|
|
8412
8567
|
console.log("");
|
|
8413
8568
|
const heHeader = padRight(
|
|
8414
|
-
" " +
|
|
8569
|
+
" " + pc3.bold(heChain.name),
|
|
8415
8570
|
colWidth + 10
|
|
8416
8571
|
/* account for ANSI */
|
|
8417
8572
|
);
|
|
8418
|
-
const mantleHeader =
|
|
8573
|
+
const mantleHeader = pc3.bold(mantleChain.name);
|
|
8419
8574
|
console.log(heHeader + " " + mantleHeader);
|
|
8420
|
-
const heDivider = padRight(" " +
|
|
8421
|
-
const mantleDivider =
|
|
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 === "?" ?
|
|
8430
|
-
const mantleColored = mantleEntry ? mantleEntry.balance === "0.00" || mantleEntry.balance === "?" ?
|
|
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(" " +
|
|
8438
|
-
console.log(" " +
|
|
8439
|
-
console.log(" " +
|
|
8440
|
-
console.log(" " +
|
|
8441
|
-
console.log(" " +
|
|
8442
|
-
console.log(" " +
|
|
8443
|
-
console.log(" " +
|
|
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
|
-
|
|
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
|
}
|