@sherwoodagent/cli 0.17.1 → 0.17.2

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 CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  setVotingPeriod,
30
30
  settleProposal,
31
31
  vote
32
- } from "./chunk-A4F6KTXA.js";
32
+ } from "./chunk-4GTOZMVG.js";
33
33
  import {
34
34
  fetchMetadata,
35
35
  uploadMetadata
@@ -41,7 +41,7 @@ import {
41
41
  queryApprovals,
42
42
  queryJoinRequests,
43
43
  revokeAttestation
44
- } from "./chunk-X3L57WGW.js";
44
+ } from "./chunk-RAFAIAIE.js";
45
45
  import {
46
46
  approveDepositor,
47
47
  deposit,
@@ -57,7 +57,7 @@ import {
57
57
  resolveVaultSyndicate,
58
58
  setTextRecord,
59
59
  setVaultAddress
60
- } from "./chunk-EMPYAZNP.js";
60
+ } from "./chunk-E7KKGN3V.js";
61
61
  import {
62
62
  AERODROME,
63
63
  AGENT_REGISTRY,
@@ -74,7 +74,7 @@ import {
74
74
  UNISWAP_QUOTER_V2_ABI,
75
75
  VENICE,
76
76
  VENICE_STAKING_ABI
77
- } from "./chunk-UQKNCRDW.js";
77
+ } from "./chunk-E3UCNLU3.js";
78
78
  import {
79
79
  getAccount,
80
80
  getPublicClient,
@@ -380,6 +380,61 @@ function buildSettleCalls3(clone) {
380
380
  ];
381
381
  }
382
382
 
383
+ // src/strategies/wsteth-moonwell-template.ts
384
+ import { encodeAbiParameters as encodeAbiParameters4, encodeFunctionData as encodeFunctionData4 } from "viem";
385
+ var INIT_PARAMS_TYPES3 = [
386
+ {
387
+ type: "tuple",
388
+ components: [
389
+ { name: "weth", type: "address" },
390
+ { name: "wsteth", type: "address" },
391
+ { name: "mwsteth", type: "address" },
392
+ { name: "aeroRouter", type: "address" },
393
+ { name: "aeroFactory", type: "address" },
394
+ { name: "supplyAmount", type: "uint256" },
395
+ { name: "minWstethOut", type: "uint256" },
396
+ { name: "minWethOut", type: "uint256" },
397
+ { name: "deadlineOffset", type: "uint256" }
398
+ ]
399
+ }
400
+ ];
401
+ function buildInitData4(params) {
402
+ return encodeAbiParameters4(INIT_PARAMS_TYPES3, [params]);
403
+ }
404
+ function buildExecuteCalls4(clone, weth, supplyAmount) {
405
+ return [
406
+ {
407
+ target: weth,
408
+ data: encodeFunctionData4({
409
+ abi: ERC20_ABI,
410
+ functionName: "approve",
411
+ args: [clone, supplyAmount]
412
+ }),
413
+ value: 0n
414
+ },
415
+ {
416
+ target: clone,
417
+ data: encodeFunctionData4({
418
+ abi: BASE_STRATEGY_ABI,
419
+ functionName: "execute"
420
+ }),
421
+ value: 0n
422
+ }
423
+ ];
424
+ }
425
+ function buildSettleCalls4(clone) {
426
+ return [
427
+ {
428
+ target: clone,
429
+ data: encodeFunctionData4({
430
+ abi: BASE_STRATEGY_ABI,
431
+ functionName: "settle"
432
+ }),
433
+ value: 0n
434
+ }
435
+ ];
436
+ }
437
+
383
438
  // src/commands/strategy-template.ts
384
439
  var ZERO = "0x0000000000000000000000000000000000000000";
385
440
  var TEMPLATES = [
@@ -400,6 +455,12 @@ var TEMPLATES = [
400
455
  key: "venice-inference",
401
456
  description: "Stake VVV for sVVV \u2014 Venice private AI inference",
402
457
  addressKey: "VENICE_INFERENCE"
458
+ },
459
+ {
460
+ name: "wstETH Moonwell Yield",
461
+ key: "wsteth-moonwell",
462
+ description: "WETH \u2192 wstETH \u2192 Moonwell \u2014 stack Lido + lending yield",
463
+ addressKey: "WSTETH_MOONWELL"
403
464
  }
404
465
  ];
405
466
  function resolveTemplate(key) {
@@ -506,6 +567,32 @@ async function buildInitDataForTemplate(templateKey, opts, vault) {
506
567
  extraApprovals: [{ token: tokenB, amount: amountB }]
507
568
  };
508
569
  }
570
+ if (templateKey === "wsteth-moonwell") {
571
+ if (!opts.amount) {
572
+ console.error(chalk.red("--amount is required for wsteth-moonwell template"));
573
+ process.exit(1);
574
+ }
575
+ const supplyAmount = parseUnits(opts.amount, 18);
576
+ const slippageBps = BigInt(opts.slippage || "500");
577
+ const minWstethOut = supplyAmount - supplyAmount * slippageBps / 10000n;
578
+ const minWethOut = supplyAmount - supplyAmount * slippageBps / 10000n;
579
+ const params = {
580
+ weth: TOKENS().WETH,
581
+ wsteth: TOKENS().wstETH,
582
+ mwsteth: MOONWELL().mWstETH,
583
+ aeroRouter: AERODROME().ROUTER,
584
+ aeroFactory: AERODROME().FACTORY,
585
+ supplyAmount,
586
+ minWstethOut,
587
+ minWethOut,
588
+ deadlineOffset: 300n
589
+ };
590
+ return {
591
+ initData: buildInitData4(params),
592
+ asset: TOKENS().WETH,
593
+ assetAmount: supplyAmount
594
+ };
595
+ }
509
596
  throw new Error(`No init builder for template: ${templateKey}`);
510
597
  }
511
598
  function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraApprovals) {
@@ -529,6 +616,12 @@ function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraAppr
529
616
  settleCalls: buildSettleCalls3(clone)
530
617
  };
531
618
  }
619
+ if (templateKey === "wsteth-moonwell") {
620
+ return {
621
+ executeCalls: buildExecuteCalls4(clone, asset, assetAmount),
622
+ settleCalls: buildSettleCalls4(clone)
623
+ };
624
+ }
532
625
  throw new Error(`No call builder for template: ${templateKey}`);
533
626
  }
534
627
  function resolveToken(symbolOrAddress) {
@@ -593,7 +686,7 @@ function registerStrategyTemplateCommands(strategy2) {
593
686
  console.log(chalk.dim("Full proposal: sherwood strategy propose <template> --vault <addr> ..."));
594
687
  console.log();
595
688
  });
596
- strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference").requiredOption("--vault <address>", "Vault address").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").action(async (templateKey, opts) => {
689
+ strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell").requiredOption("--vault <address>", "Vault address").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").option("--slippage <bps>", "Slippage tolerance in bps (wstETH, default: 500 = 5%)").action(async (templateKey, opts) => {
597
690
  const vault = opts.vault;
598
691
  if (!isAddress(vault)) {
599
692
  console.error(chalk.red("Invalid vault address"));
@@ -639,7 +732,7 @@ function registerStrategyTemplateCommands(strategy2) {
639
732
  console.log(chalk.dim("Use this address in your proposal batch calls."));
640
733
  console.log();
641
734
  });
642
- strategy2.command("propose").description("Clone + init + build calls + submit governance proposal (all-in-one)").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference").requiredOption("--vault <address>", "Vault address").option("--write-calls <dir>", "Write execute/settle JSON to directory (skip proposal submission)").option("--name <name>", "Proposal name").option("--description <text>", "Proposal description").option("--performance-fee <bps>", "Agent fee in bps").option("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").action(async (templateKey, opts) => {
735
+ strategy2.command("propose").description("Clone + init + build calls + submit governance proposal (all-in-one)").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell").requiredOption("--vault <address>", "Vault address").option("--write-calls <dir>", "Write execute/settle JSON to directory (skip proposal submission)").option("--name <name>", "Proposal name").option("--description <text>", "Proposal description").option("--performance-fee <bps>", "Agent fee in bps").option("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").option("--slippage <bps>", "Slippage tolerance in bps (wstETH, default: 500 = 5%)").action(async (templateKey, opts) => {
643
736
  const vault = opts.vault;
644
737
  if (!isAddress(vault)) {
645
738
  console.error(chalk.red("Invalid vault address"));
@@ -717,8 +810,9 @@ function registerStrategyTemplateCommands(strategy2) {
717
810
  console.log(chalk.dim(` --settle-calls ${settlePath}`));
718
811
  if (templateKey === "venice-inference") {
719
812
  console.log();
720
- console.log(chalk.yellow("Reminder: agent must pre-approve sVVV clawback:"));
721
- console.log(chalk.yellow(` sVVV.approve(${clone}, <amount>)`));
813
+ console.log(chalk.yellow("Reminder: before settlement, agent must approve repayment:"));
814
+ console.log(chalk.yellow(` asset.approve(${clone}, <repaymentAmount>)`));
815
+ console.log(chalk.yellow(" Agent can update repayment via strategy.updateParams(newRepayment, 0, 0)"));
722
816
  }
723
817
  console.log();
724
818
  return;
@@ -727,9 +821,9 @@ function registerStrategyTemplateCommands(strategy2) {
727
821
  console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
728
822
  process.exit(1);
729
823
  }
730
- const { propose: propose2 } = await import("./governor-P6YV4YR7.js");
824
+ const { propose: propose2 } = await import("./governor-J7WTADUX.js");
731
825
  const { pinJSON } = await import("./ipfs-6XVOOHSR.js");
732
- const { parseDuration: parseDuration2 } = await import("./governor-P6YV4YR7.js");
826
+ const { parseDuration: parseDuration2 } = await import("./governor-J7WTADUX.js");
733
827
  const performanceFeeBps = BigInt(opts.performanceFee);
734
828
  if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
735
829
  console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
@@ -779,9 +873,10 @@ function registerStrategyTemplateCommands(strategy2) {
779
873
  if (templateKey === "venice-inference") {
780
874
  console.log();
781
875
  console.log(chalk.yellow("Next steps:"));
782
- console.log(chalk.yellow(` 1. Pre-approve sVVV clawback: sVVV.approve(${clone}, <amount>)`));
783
- console.log(chalk.yellow(" 2. After execution: sherwood venice provision"));
784
- console.log(chalk.yellow(" 3. Use inference: sherwood venice infer --model <id> --prompt '...'"));
876
+ console.log(chalk.yellow(" 1. After execution: sherwood venice provision"));
877
+ console.log(chalk.yellow(" 2. Use inference: sherwood venice infer --model <id> --prompt '...'"));
878
+ console.log(chalk.yellow(" 3. Before settlement: approve repayment (principal + profit):"));
879
+ console.log(chalk.yellow(` asset.approve(${clone}, <repaymentAmount>)`));
785
880
  }
786
881
  console.log();
787
882
  });
@@ -970,10 +1065,10 @@ import chalk2 from "chalk";
970
1065
  import ora2 from "ora";
971
1066
 
972
1067
  // src/lib/quote.ts
973
- import { encodeFunctionData as encodeFunctionData4, decodeFunctionResult, concat as concat2, pad, numberToHex } from "viem";
1068
+ import { encodeFunctionData as encodeFunctionData5, decodeFunctionResult, concat as concat2, pad, numberToHex } from "viem";
974
1069
  async function getQuote(params) {
975
1070
  const client = getPublicClient();
976
- const calldata = encodeFunctionData4({
1071
+ const calldata = encodeFunctionData5({
977
1072
  abi: UNISWAP_QUOTER_V2_ABI,
978
1073
  functionName: "quoteExactInputSingle",
979
1074
  args: [
@@ -1018,7 +1113,7 @@ function encodeSwapPath(tokens, fees) {
1018
1113
  }
1019
1114
  async function getMultiHopQuote(params) {
1020
1115
  const client = getPublicClient();
1021
- const calldata = encodeFunctionData4({
1116
+ const calldata = encodeFunctionData5({
1022
1117
  abi: UNISWAP_QUOTER_V2_ABI,
1023
1118
  functionName: "quoteExactInput",
1024
1119
  args: [params.path, params.amountIn]
@@ -1039,7 +1134,7 @@ async function getMultiHopQuote(params) {
1039
1134
  }
1040
1135
 
1041
1136
  // src/strategies/venice-fund.ts
1042
- import { encodeFunctionData as encodeFunctionData5, parseUnits as parseUnits3 } from "viem";
1137
+ import { encodeFunctionData as encodeFunctionData6, parseUnits as parseUnits3 } from "viem";
1043
1138
  var ERC20_ABI2 = [
1044
1139
  {
1045
1140
  name: "approve",
@@ -1113,7 +1208,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
1113
1208
  const calls = [];
1114
1209
  calls.push({
1115
1210
  target: assetAddress,
1116
- data: encodeFunctionData5({
1211
+ data: encodeFunctionData6({
1117
1212
  abi: ERC20_ABI2,
1118
1213
  functionName: "approve",
1119
1214
  args: [UNISWAP().SWAP_ROUTER, assetAmount]
@@ -1123,7 +1218,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
1123
1218
  if (isWeth) {
1124
1219
  calls.push({
1125
1220
  target: UNISWAP().SWAP_ROUTER,
1126
- data: encodeFunctionData5({
1221
+ data: encodeFunctionData6({
1127
1222
  abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
1128
1223
  functionName: "exactInputSingle",
1129
1224
  args: [
@@ -1143,7 +1238,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
1143
1238
  } else {
1144
1239
  calls.push({
1145
1240
  target: UNISWAP().SWAP_ROUTER,
1146
- data: encodeFunctionData5({
1241
+ data: encodeFunctionData6({
1147
1242
  abi: SWAP_ROUTER_EXACT_INPUT_ABI,
1148
1243
  functionName: "exactInput",
1149
1244
  args: [
@@ -1160,7 +1255,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
1160
1255
  }
1161
1256
  calls.push({
1162
1257
  target: VENICE().VVV,
1163
- data: encodeFunctionData5({
1258
+ data: encodeFunctionData6({
1164
1259
  abi: ERC20_ABI2,
1165
1260
  functionName: "approve",
1166
1261
  args: [VENICE().STAKING, minVVV]
@@ -1171,7 +1266,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
1171
1266
  for (const agent of agents) {
1172
1267
  calls.push({
1173
1268
  target: VENICE().STAKING,
1174
- data: encodeFunctionData5({
1269
+ data: encodeFunctionData6({
1175
1270
  abi: STAKING_ABI,
1176
1271
  functionName: "stake",
1177
1272
  args: [agent, perAgent]
@@ -1624,7 +1719,7 @@ import chalk3 from "chalk";
1624
1719
  import ora3 from "ora";
1625
1720
 
1626
1721
  // src/strategies/allowance-disburse.ts
1627
- import { encodeFunctionData as encodeFunctionData6, parseUnits as parseUnits5 } from "viem";
1722
+ import { encodeFunctionData as encodeFunctionData7, parseUnits as parseUnits5 } from "viem";
1628
1723
  var ERC20_ABI3 = [
1629
1724
  {
1630
1725
  name: "approve",
@@ -1694,7 +1789,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1694
1789
  if (!isUsdc) {
1695
1790
  calls.push({
1696
1791
  target: assetAddress,
1697
- data: encodeFunctionData6({
1792
+ data: encodeFunctionData7({
1698
1793
  abi: ERC20_ABI3,
1699
1794
  functionName: "approve",
1700
1795
  args: [UNISWAP().SWAP_ROUTER, assetAmount]
@@ -1704,7 +1799,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1704
1799
  if (isWeth) {
1705
1800
  calls.push({
1706
1801
  target: UNISWAP().SWAP_ROUTER,
1707
- data: encodeFunctionData6({
1802
+ data: encodeFunctionData7({
1708
1803
  abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI2,
1709
1804
  functionName: "exactInputSingle",
1710
1805
  args: [
@@ -1724,7 +1819,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1724
1819
  } else {
1725
1820
  calls.push({
1726
1821
  target: UNISWAP().SWAP_ROUTER,
1727
- data: encodeFunctionData6({
1822
+ data: encodeFunctionData7({
1728
1823
  abi: SWAP_ROUTER_EXACT_INPUT_ABI2,
1729
1824
  functionName: "exactInput",
1730
1825
  args: [
@@ -1744,7 +1839,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1744
1839
  for (const agent of agents) {
1745
1840
  calls.push({
1746
1841
  target: TOKENS().USDC,
1747
- data: encodeFunctionData6({
1842
+ data: encodeFunctionData7({
1748
1843
  abi: ERC20_ABI3,
1749
1844
  functionName: "transfer",
1750
1845
  args: [agent, perAgent]
@@ -2640,7 +2735,7 @@ try {
2640
2735
  var require2 = createRequire(import.meta.url);
2641
2736
  var { version: CLI_VERSION } = require2("../package.json");
2642
2737
  async function loadXmtp() {
2643
- return import("./xmtp-DX73F6I4.js");
2738
+ return import("./xmtp-2AHDKL2Q.js");
2644
2739
  }
2645
2740
  async function loadCron() {
2646
2741
  return import("./cron-SKYKVZ6K.js");
@@ -3383,7 +3478,7 @@ ${info.name} (${info.type})`);
3383
3478
  }
3384
3479
  });
3385
3480
  try {
3386
- const { registerChatCommands } = await import("./chat-G5TRNY5S.js");
3481
+ const { registerChatCommands } = await import("./chat-XTOTPTGV.js");
3387
3482
  registerChatCommands(program);
3388
3483
  } catch {
3389
3484
  program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
@@ -3393,14 +3488,14 @@ try {
3393
3488
  process.exit(1);
3394
3489
  });
3395
3490
  }
3396
- var { registerSessionCommands } = await import("./session-VEF5BZIX.js");
3491
+ var { registerSessionCommands } = await import("./session-RDBY24HJ.js");
3397
3492
  registerSessionCommands(program);
3398
3493
  registerVeniceCommands(program);
3399
3494
  registerAllowanceCommands(program);
3400
3495
  registerIdentityCommands(program);
3401
3496
  registerProposalCommands(program);
3402
3497
  registerGovernorCommands(program);
3403
- var { registerResearchCommands } = await import("./research-FNH3VT57.js");
3498
+ var { registerResearchCommands } = await import("./research-BYQZ2MLK.js");
3404
3499
  registerResearchCommands(program);
3405
3500
  var configCmd = program.command("config");
3406
3501
  configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").option("--rpc <url>", "Custom RPC URL for the active --chain network").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").action((opts) => {