@sherwoodagent/cli 0.22.7 → 0.24.0

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.
Files changed (49) hide show
  1. package/dist/{chat-JYAJMP4D.js → chat-3SAX4VRO.js} +7 -7
  2. package/dist/{chunk-LVPBJ7MI.js → chunk-35536GNW.js} +2 -2
  3. package/dist/{chunk-4Y6Y4SVH.js → chunk-5NN424VN.js} +4 -4
  4. package/dist/{chunk-B42ZCCZ7.js → chunk-5S2TBADL.js} +4 -2
  5. package/dist/chunk-5S2TBADL.js.map +1 -0
  6. package/dist/{chunk-VO6DCRWV.js → chunk-LMDHM36X.js} +4 -4
  7. package/dist/{chunk-QGZUMIVO.js → chunk-NGET2RWT.js} +16 -7
  8. package/dist/chunk-NGET2RWT.js.map +1 -0
  9. package/dist/{chunk-Y7LS6DEF.js → chunk-PEJPTKLK.js} +5 -5
  10. package/dist/{chunk-JR5K5WVR.js → chunk-R75DM3VL.js} +163 -10
  11. package/dist/chunk-R75DM3VL.js.map +1 -0
  12. package/dist/{chunk-ASJTFFZH.js → chunk-R7Q2L6VV.js} +3 -3
  13. package/dist/{chunk-G7JQRLQE.js → chunk-ZIH3SCFJ.js} +5 -5
  14. package/dist/{client-SCIY6SUP.js → client-XG6LL6TS.js} +4 -4
  15. package/dist/{config-BGS5MX4D.js → config-EHCEKT2B.js} +2 -2
  16. package/dist/{eas-X5UIEM6D.js → eas-ZMTIOZH6.js} +6 -6
  17. package/dist/{governor-ZKRSAHG4.js → governor-JIXAG6WU.js} +6 -6
  18. package/dist/index.js +609 -74
  19. package/dist/index.js.map +1 -1
  20. package/dist/{network-UTSOP7EF.js → network-UVMYTKQX.js} +3 -3
  21. package/dist/price-AGCWXLZ6.js +156 -0
  22. package/dist/price-AGCWXLZ6.js.map +1 -0
  23. package/dist/research-2I6AA3BI.js +14 -0
  24. package/dist/{research-ZW6XVTGZ.js → research-KUIZM6AK.js} +9 -9
  25. package/dist/{session-XZNKLK3I.js → session-2FIR4LJP.js} +12 -12
  26. package/dist/{trade-OJM5HNHL.js → trade-UTM3DSO3.js} +16 -16
  27. package/dist/{xmtp-XKHXATPQ.js → xmtp-B2XFVPIV.js} +6 -6
  28. package/package.json +1 -1
  29. package/dist/chunk-B42ZCCZ7.js.map +0 -1
  30. package/dist/chunk-JR5K5WVR.js.map +0 -1
  31. package/dist/chunk-QGZUMIVO.js.map +0 -1
  32. package/dist/research-SJ6D3L2B.js +0 -14
  33. /package/dist/{chat-JYAJMP4D.js.map → chat-3SAX4VRO.js.map} +0 -0
  34. /package/dist/{chunk-LVPBJ7MI.js.map → chunk-35536GNW.js.map} +0 -0
  35. /package/dist/{chunk-4Y6Y4SVH.js.map → chunk-5NN424VN.js.map} +0 -0
  36. /package/dist/{chunk-VO6DCRWV.js.map → chunk-LMDHM36X.js.map} +0 -0
  37. /package/dist/{chunk-Y7LS6DEF.js.map → chunk-PEJPTKLK.js.map} +0 -0
  38. /package/dist/{chunk-ASJTFFZH.js.map → chunk-R7Q2L6VV.js.map} +0 -0
  39. /package/dist/{chunk-G7JQRLQE.js.map → chunk-ZIH3SCFJ.js.map} +0 -0
  40. /package/dist/{client-SCIY6SUP.js.map → client-XG6LL6TS.js.map} +0 -0
  41. /package/dist/{config-BGS5MX4D.js.map → config-EHCEKT2B.js.map} +0 -0
  42. /package/dist/{eas-X5UIEM6D.js.map → eas-ZMTIOZH6.js.map} +0 -0
  43. /package/dist/{governor-ZKRSAHG4.js.map → governor-JIXAG6WU.js.map} +0 -0
  44. /package/dist/{network-UTSOP7EF.js.map → network-UVMYTKQX.js.map} +0 -0
  45. /package/dist/{research-SJ6D3L2B.js.map → research-2I6AA3BI.js.map} +0 -0
  46. /package/dist/{research-ZW6XVTGZ.js.map → research-KUIZM6AK.js.map} +0 -0
  47. /package/dist/{session-XZNKLK3I.js.map → session-2FIR4LJP.js.map} +0 -0
  48. /package/dist/{trade-OJM5HNHL.js.map → trade-UTM3DSO3.js.map} +0 -0
  49. /package/dist/{xmtp-XKHXATPQ.js.map → xmtp-B2XFVPIV.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,4 +1,22 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ approveDepositor,
4
+ deposit,
5
+ depositWithEthWrap,
6
+ executeBatch,
7
+ getAssetDecimals,
8
+ getBalance,
9
+ getVaultAddress,
10
+ getVaultInfo,
11
+ isAgent,
12
+ preflightDeposit,
13
+ registerAgent,
14
+ removeDepositor,
15
+ resolveSyndicate,
16
+ resolveVaultSyndicate,
17
+ setTextRecord,
18
+ setVaultAddress
19
+ } from "./chunk-ZIH3SCFJ.js";
2
20
  import {
3
21
  UniswapProvider,
4
22
  applySlippage,
@@ -9,7 +27,7 @@ import {
9
27
  getQuote,
10
28
  listModels,
11
29
  provisionApiKey
12
- } from "./chunk-Y7LS6DEF.js";
30
+ } from "./chunk-PEJPTKLK.js";
13
31
  import {
14
32
  PROPOSAL_STATE,
15
33
  PROPOSAL_STATES,
@@ -40,7 +58,7 @@ import {
40
58
  setVotingPeriod,
41
59
  settleProposal,
42
60
  vote
43
- } from "./chunk-VO6DCRWV.js";
61
+ } from "./chunk-LMDHM36X.js";
44
62
  import {
45
63
  fetchMetadata,
46
64
  uploadMetadata
@@ -54,43 +72,28 @@ import {
54
72
  queryJoinRequests,
55
73
  revokeAttestation,
56
74
  stripReferrerPrefix
57
- } from "./chunk-4Y6Y4SVH.js";
58
- import {
59
- approveDepositor,
60
- deposit,
61
- depositWithEthWrap,
62
- executeBatch,
63
- getAssetDecimals,
64
- getBalance,
65
- getVaultAddress,
66
- getVaultInfo,
67
- isAgent,
68
- preflightDeposit,
69
- registerAgent,
70
- removeDepositor,
71
- resolveSyndicate,
72
- resolveVaultSyndicate,
73
- setTextRecord,
74
- setVaultAddress
75
- } from "./chunk-G7JQRLQE.js";
75
+ } from "./chunk-5NN424VN.js";
76
76
  import {
77
77
  AERODROME,
78
78
  AGENT_REGISTRY,
79
79
  BASE_STRATEGY_ABI,
80
+ CHAINLINK,
80
81
  EAS_SCHEMAS,
81
82
  ERC20_ABI,
82
83
  MOONWELL,
84
+ PORTFOLIO_STRATEGY_ABI,
83
85
  SHERWOOD,
84
86
  STRATEGY_TEMPLATES,
85
87
  SWAP_ROUTER_ABI,
86
88
  SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
87
89
  SYNDICATE_FACTORY_ABI,
88
90
  SYNDICATE_VAULT_ABI,
91
+ SYNTHRA,
89
92
  TOKENS,
90
93
  UNISWAP,
91
94
  VENICE,
92
95
  VENICE_STAKING_ABI
93
- } from "./chunk-JR5K5WVR.js";
96
+ } from "./chunk-R75DM3VL.js";
94
97
  import {
95
98
  formatContractError,
96
99
  getAccount,
@@ -98,7 +101,7 @@ import {
98
101
  sendTxWithRetry,
99
102
  waitForReceipt,
100
103
  writeContractWithRetry
101
- } from "./chunk-ASJTFFZH.js";
104
+ } from "./chunk-R7Q2L6VV.js";
102
105
  import {
103
106
  VALID_NETWORKS,
104
107
  getChain,
@@ -107,7 +110,7 @@ import {
107
110
  getRpcUrl,
108
111
  isTestnet,
109
112
  setNetwork
110
- } from "./chunk-LVPBJ7MI.js";
113
+ } from "./chunk-35536GNW.js";
111
114
  import {
112
115
  addSyndicate,
113
116
  cacheGroupId,
@@ -127,7 +130,7 @@ import {
127
130
  setPrivateKey,
128
131
  setUniswapApiKey,
129
132
  setVeniceApiKey
130
- } from "./chunk-B42ZCCZ7.js";
133
+ } from "./chunk-5S2TBADL.js";
131
134
 
132
135
  // src/index.ts
133
136
  import { config as loadDotenv } from "dotenv";
@@ -173,7 +176,7 @@ var MoonwellProvider = class {
173
176
  };
174
177
 
175
178
  // src/commands/strategy-template.ts
176
- import { parseUnits, isAddress, erc20Abi } from "viem";
179
+ import { parseUnits, formatUnits, isAddress, erc20Abi, encodeAbiParameters as encodeAbiParameters7, decodeAbiParameters } from "viem";
177
180
  import chalk from "chalk";
178
181
  import ora from "ora";
179
182
  import { writeFileSync, mkdirSync } from "fs";
@@ -483,6 +486,69 @@ function buildSettleCalls5(clone) {
483
486
  ];
484
487
  }
485
488
 
489
+ // src/strategies/portfolio-template.ts
490
+ import { encodeAbiParameters as encodeAbiParameters6, encodeFunctionData as encodeFunctionData6 } from "viem";
491
+ function buildInitData6(asset, swapAdapter, chainlinkVerifier, allocations, totalAmount, maxSlippageBps) {
492
+ const tokens = allocations.map((a) => a.token);
493
+ const weightsBps = allocations.map((a) => BigInt(a.weightBps));
494
+ const swapExtraData = allocations.map((a) => a.swapExtraData);
495
+ return encodeAbiParameters6(
496
+ [
497
+ { type: "address" },
498
+ { type: "address" },
499
+ { type: "address" },
500
+ { type: "address[]" },
501
+ { type: "uint256[]" },
502
+ { type: "uint256" },
503
+ { type: "uint256" },
504
+ { type: "bytes[]" }
505
+ ],
506
+ [
507
+ asset,
508
+ swapAdapter,
509
+ chainlinkVerifier,
510
+ tokens,
511
+ weightsBps,
512
+ totalAmount,
513
+ BigInt(maxSlippageBps),
514
+ swapExtraData
515
+ ]
516
+ );
517
+ }
518
+ function buildExecuteCalls6(clone, asset, totalAmount) {
519
+ return [
520
+ {
521
+ target: asset,
522
+ data: encodeFunctionData6({
523
+ abi: ERC20_ABI,
524
+ functionName: "approve",
525
+ args: [clone, totalAmount]
526
+ }),
527
+ value: 0n
528
+ },
529
+ {
530
+ target: clone,
531
+ data: encodeFunctionData6({
532
+ abi: BASE_STRATEGY_ABI,
533
+ functionName: "execute"
534
+ }),
535
+ value: 0n
536
+ }
537
+ ];
538
+ }
539
+ function buildSettleCalls6(clone) {
540
+ return [
541
+ {
542
+ target: clone,
543
+ data: encodeFunctionData6({
544
+ abi: BASE_STRATEGY_ABI,
545
+ functionName: "settle"
546
+ }),
547
+ value: 0n
548
+ }
549
+ ];
550
+ }
551
+
486
552
  // src/commands/strategy-template.ts
487
553
  var ZERO = "0x0000000000000000000000000000000000000000";
488
554
  var TEMPLATES = [
@@ -515,6 +581,12 @@ var TEMPLATES = [
515
581
  key: "mamo-yield",
516
582
  description: "Deposit into Mamo for optimized yield across Moonwell + Morpho vaults",
517
583
  addressKey: "MAMO_YIELD"
584
+ },
585
+ {
586
+ name: "Portfolio",
587
+ key: "portfolio",
588
+ description: "Weighted portfolio of tokens (stock tokens, crypto) with rebalancing",
589
+ addressKey: "PORTFOLIO"
518
590
  }
519
591
  ];
520
592
  function resolveTemplate(key) {
@@ -709,6 +781,54 @@ async function buildInitDataForTemplate(templateKey, opts, vault) {
709
781
  assetAmount: amount
710
782
  };
711
783
  }
784
+ if (templateKey === "portfolio") {
785
+ if (!opts.amount) {
786
+ console.error(chalk.red("--amount is required for portfolio template"));
787
+ process.exit(1);
788
+ }
789
+ if (!opts.tokens || !opts.weights) {
790
+ console.error(chalk.red("--tokens and --weights are required for portfolio template"));
791
+ console.error(chalk.dim(" --tokens: comma-separated token addresses or symbols"));
792
+ console.error(chalk.dim(" --weights: comma-separated bps (must sum to 10000)"));
793
+ process.exit(1);
794
+ }
795
+ const tokens = TOKENS();
796
+ const asset = resolveToken(opts.asset || "WETH");
797
+ const decimals = opts.asset?.toUpperCase() === "USDC" ? 6 : 18;
798
+ const totalAmount = parseUnits(opts.amount, decimals);
799
+ const maxSlippageBps = Number(opts.maxSlippage || "500");
800
+ const feeTier = opts.feeTier || "3000";
801
+ const tokenAddrs = opts.tokens.split(",").map((t) => {
802
+ const trimmed = t.trim();
803
+ if (isAddress(trimmed)) return trimmed;
804
+ const allTokens = tokens;
805
+ const resolved = allTokens[trimmed.toUpperCase()];
806
+ if (resolved && resolved !== ZERO) return resolved;
807
+ console.error(chalk.red(`Unknown token: ${trimmed}`));
808
+ process.exit(1);
809
+ });
810
+ const weightsBps = opts.weights.split(",").map((w) => Number(w.trim()));
811
+ if (tokenAddrs.length !== weightsBps.length) {
812
+ console.error(chalk.red("--tokens and --weights must have same length"));
813
+ process.exit(1);
814
+ }
815
+ if (weightsBps.reduce((a, b) => a + b, 0) !== 1e4) {
816
+ console.error(chalk.red(`Weights must sum to 10000`));
817
+ process.exit(1);
818
+ }
819
+ const swapAdapter = opts.swapAdapter || resolveSwapAdapter();
820
+ const chainlinkVerifier = CHAINLINK().VERIFIER_PROXY;
821
+ const allocations = tokenAddrs.map((token, i) => ({
822
+ token,
823
+ weightBps: weightsBps[i],
824
+ swapExtraData: encodeAbiParameters7([{ type: "uint24" }], [Number(feeTier)])
825
+ }));
826
+ return {
827
+ initData: buildInitData6(asset, swapAdapter, chainlinkVerifier, allocations, totalAmount, maxSlippageBps),
828
+ asset,
829
+ assetAmount: totalAmount
830
+ };
831
+ }
712
832
  throw new Error(`No init builder for template: ${templateKey}`);
713
833
  }
714
834
  function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraApprovals) {
@@ -744,8 +864,30 @@ function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraAppr
744
864
  settleCalls: buildSettleCalls5(clone)
745
865
  };
746
866
  }
867
+ if (templateKey === "portfolio") {
868
+ return {
869
+ executeCalls: buildExecuteCalls6(clone, asset, assetAmount),
870
+ settleCalls: buildSettleCalls6(clone)
871
+ };
872
+ }
747
873
  throw new Error(`No call builder for template: ${templateKey}`);
748
874
  }
875
+ function resolveSwapAdapter() {
876
+ const network = getNetwork();
877
+ if (network === "robinhood-testnet") {
878
+ if (SYNTHRA().ROUTER === ZERO) {
879
+ console.error(chalk.red("Synthra DEX not available"));
880
+ process.exit(1);
881
+ }
882
+ return "0xdae81cDCfcB14c56fCeB788A147Fcd6CbEdfEeca";
883
+ }
884
+ if (UNISWAP().SWAP_ROUTER === ZERO) {
885
+ console.error(chalk.red("No swap adapter available"));
886
+ process.exit(1);
887
+ }
888
+ console.error(chalk.red("UniswapSwapAdapter not deployed yet. Use --swap-adapter to specify manually."));
889
+ process.exit(1);
890
+ }
749
891
  function resolveToken(symbolOrAddress) {
750
892
  if (isAddress(symbolOrAddress)) return symbolOrAddress;
751
893
  const upper = symbolOrAddress.toUpperCase();
@@ -792,23 +934,39 @@ function serializeCalls(calls) {
792
934
  function registerStrategyTemplateCommands(strategy2) {
793
935
  strategy2.command("list").description("List available strategy templates").action(() => {
794
936
  const templates = STRATEGY_TEMPLATES();
937
+ const network = getNetwork();
795
938
  console.log();
796
- console.log(chalk.bold("Strategy Templates"));
939
+ console.log(chalk.bold("Strategy Templates"), chalk.dim(`(${network})`));
797
940
  console.log(chalk.dim("\u2500".repeat(60)));
941
+ let availableCount = 0;
798
942
  for (const t of TEMPLATES) {
799
943
  const addr = templates[t.addressKey];
800
- const deployed = addr !== ZERO;
944
+ if (addr !== ZERO) {
945
+ availableCount++;
946
+ console.log();
947
+ console.log(` ${chalk.bold(t.name)} (${chalk.cyan(t.key)})`);
948
+ console.log(` ${t.description}`);
949
+ console.log(` Template: ${chalk.green(addr)}`);
950
+ }
951
+ }
952
+ if (availableCount === 0) {
801
953
  console.log();
802
- console.log(` ${chalk.bold(t.name)} (${chalk.cyan(t.key)})`);
803
- console.log(` ${t.description}`);
804
- console.log(` Template: ${deployed ? chalk.green(addr) : chalk.red("not deployed")}`);
954
+ console.log(chalk.yellow(" No strategy templates deployed on this network."));
955
+ }
956
+ const unavailable = TEMPLATES.filter((t) => templates[t.addressKey] === ZERO);
957
+ if (unavailable.length > 0) {
958
+ console.log();
959
+ console.log(chalk.dim(` Not available on ${network}:`));
960
+ for (const t of unavailable) {
961
+ console.log(chalk.dim(` ${t.name} (${t.key})`));
962
+ }
805
963
  }
806
964
  console.log();
807
965
  console.log(chalk.dim("Clone a template: sherwood strategy clone <template> --vault <addr> ..."));
808
966
  console.log(chalk.dim("Full proposal: sherwood strategy propose <template> --vault <addr> ..."));
809
967
  console.log();
810
968
  });
811
- strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell, mamo-yield").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").action(async (templateKey, opts) => {
969
+ strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell, mamo-yield, portfolio").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").option("--tokens <list>", "Comma-separated token addresses or symbols (Portfolio)").option("--weights <list>", "Comma-separated weights in bps, must sum to 10000 (Portfolio)").option("--max-slippage <bps>", "Max slippage bps (Portfolio, default: 500)").option("--fee-tier <n>", "Pool fee tier (Portfolio, default: 3000)").option("--swap-adapter <address>", "Swap adapter address (Portfolio)").action(async (templateKey, opts) => {
812
970
  const vault = opts.vault;
813
971
  if (!isAddress(vault)) {
814
972
  console.error(chalk.red("Invalid vault address"));
@@ -856,7 +1014,7 @@ function registerStrategyTemplateCommands(strategy2) {
856
1014
  console.log(chalk.dim("Use this address in your proposal batch calls."));
857
1015
  console.log();
858
1016
  });
859
- strategy2.command("init").description("Initialize an already-deployed but uninitialized strategy clone").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell, mamo-yield").requiredOption("--clone <address>", "Clone address to initialize").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").action(async (templateKey, opts) => {
1017
+ strategy2.command("init").description("Initialize an already-deployed but uninitialized strategy clone").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell, mamo-yield, portfolio").requiredOption("--clone <address>", "Clone address to initialize").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").option("--tokens <list>", "Comma-separated token addresses or symbols (Portfolio)").option("--weights <list>", "Comma-separated weights in bps, must sum to 10000 (Portfolio)").option("--max-slippage <bps>", "Max slippage bps (Portfolio, default: 500)").option("--fee-tier <n>", "Pool fee tier (Portfolio, default: 3000)").option("--swap-adapter <address>", "Swap adapter address (Portfolio)").action(async (templateKey, opts) => {
860
1018
  const clone = opts.clone;
861
1019
  const vault = opts.vault;
862
1020
  if (!isAddress(clone)) {
@@ -912,7 +1070,7 @@ function registerStrategyTemplateCommands(strategy2) {
912
1070
  console.log(` Proposer: ${chalk.green(getAccount().address)}`);
913
1071
  console.log();
914
1072
  });
915
- 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, mamo-yield").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").action(async (templateKey, opts) => {
1073
+ 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, mamo-yield, portfolio").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%)").option("--mamo-factory <address>", "Mamo StrategyFactory address (Mamo)").option("--tokens <list>", "Comma-separated token addresses or symbols (Portfolio)").option("--weights <list>", "Comma-separated weights in bps, must sum to 10000 (Portfolio)").option("--max-slippage <bps>", "Max slippage bps (Portfolio, default: 500)").option("--fee-tier <n>", "Pool fee tier (Portfolio, default: 3000)").option("--swap-adapter <address>", "Swap adapter address (Portfolio)").action(async (templateKey, opts) => {
916
1074
  const vault = opts.vault;
917
1075
  if (!isAddress(vault)) {
918
1076
  console.error(chalk.red("Invalid vault address"));
@@ -1003,9 +1161,9 @@ function registerStrategyTemplateCommands(strategy2) {
1003
1161
  console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
1004
1162
  process.exit(1);
1005
1163
  }
1006
- const { propose: propose2 } = await import("./governor-ZKRSAHG4.js");
1164
+ const { propose: propose2 } = await import("./governor-JIXAG6WU.js");
1007
1165
  const { pinJSON } = await import("./ipfs-22YLNQ2C.js");
1008
- const { parseDuration: parseDuration2 } = await import("./governor-ZKRSAHG4.js");
1166
+ const { parseDuration: parseDuration2 } = await import("./governor-JIXAG6WU.js");
1009
1167
  const performanceFeeBps = BigInt(opts.performanceFee);
1010
1168
  if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
1011
1169
  console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
@@ -1063,6 +1221,380 @@ function registerStrategyTemplateCommands(strategy2) {
1063
1221
  }
1064
1222
  console.log();
1065
1223
  });
1224
+ strategy2.command("status").description("Show portfolio strategy status \u2014 allocations, balances, drift, PnL (Portfolio only)").argument("<clone>", "Strategy clone address").option("--json", "Output machine-readable JSON for agent consumption").action(async (cloneArg, opts) => {
1225
+ if (!isAddress(cloneArg)) {
1226
+ console.error(chalk.red("Invalid clone address"));
1227
+ process.exit(1);
1228
+ }
1229
+ const clone = cloneArg;
1230
+ const publicClient = getPublicClient();
1231
+ const network = getNetwork();
1232
+ const jsonMode = !!opts.json;
1233
+ const spinner = jsonMode ? null : ora("Reading strategy state...").start();
1234
+ try {
1235
+ const [stateRaw, vault, proposer, assetAddr, totalAmount, maxSlippage, allocations, swapExtraData] = await Promise.all([
1236
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "state" }),
1237
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "vault" }),
1238
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "proposer" }),
1239
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "asset" }),
1240
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "totalAmount" }),
1241
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "maxSlippageBps" }),
1242
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "getAllocations" }),
1243
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "getSwapExtraData" })
1244
+ ]);
1245
+ const stateNames = ["Pending", "Executed", "Settled"];
1246
+ const stateStr = stateNames[Number(stateRaw)] || `Unknown(${stateRaw})`;
1247
+ const [assetDecimals, assetSymbol] = await Promise.all([
1248
+ publicClient.readContract({ address: assetAddr, abi: erc20Abi, functionName: "decimals" }),
1249
+ publicClient.readContract({ address: assetAddr, abi: erc20Abi, functionName: "symbol" })
1250
+ ]);
1251
+ const tokenReads = allocations.map((a) => Promise.all([
1252
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "balanceOf", args: [clone] }),
1253
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "symbol" }),
1254
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "decimals" })
1255
+ ]));
1256
+ const tokenData = await Promise.all(tokenReads);
1257
+ const assetBalance = await publicClient.readContract({
1258
+ address: assetAddr,
1259
+ abi: erc20Abi,
1260
+ functionName: "balanceOf",
1261
+ args: [clone]
1262
+ });
1263
+ const feeTiers = swapExtraData.map((data) => {
1264
+ try {
1265
+ const [fee] = decodeAbiParameters([{ type: "uint24" }], data);
1266
+ return Number(fee) > 0 && Number(fee) <= 1e5 ? Number(fee) : 3e3;
1267
+ } catch {
1268
+ return 3e3;
1269
+ }
1270
+ });
1271
+ let prices = [];
1272
+ let priceSource = null;
1273
+ try {
1274
+ const { getTokenPricesInAsset } = await import("./price-AGCWXLZ6.js");
1275
+ prices = await getTokenPricesInAsset({
1276
+ tokens: allocations.map((a, i) => ({
1277
+ token: a.token,
1278
+ tokenDecimals: tokenData[i][2],
1279
+ feeTier: feeTiers[i]
1280
+ })),
1281
+ asset: assetAddr,
1282
+ assetDecimals
1283
+ });
1284
+ priceSource = prices.find((p) => p !== null)?.source ?? null;
1285
+ } catch {
1286
+ }
1287
+ const pricesAvailable = prices.some((p) => p !== null);
1288
+ const assetBalanceNum = Number(formatUnits(assetBalance, assetDecimals));
1289
+ let totalPortfolioValue = assetBalanceNum;
1290
+ let totalInvested = 0n;
1291
+ const allocStatuses = allocations.map((alloc, i) => {
1292
+ const [balance, symbol, decimals] = tokenData[i];
1293
+ const balanceNum = Number(formatUnits(balance, decimals));
1294
+ const investedNum = Number(formatUnits(alloc.investedAmount, assetDecimals));
1295
+ totalInvested += alloc.investedAmount;
1296
+ const price = prices[i];
1297
+ let currentValue = null;
1298
+ if (price) {
1299
+ currentValue = balanceNum * price.price;
1300
+ totalPortfolioValue += currentValue;
1301
+ }
1302
+ return {
1303
+ token: alloc.token,
1304
+ symbol,
1305
+ decimals,
1306
+ targetWeightBps: Number(alloc.targetWeightBps),
1307
+ balance: formatUnits(balance, decimals),
1308
+ balanceRaw: balance.toString(),
1309
+ investedAmount: formatUnits(alloc.investedAmount, assetDecimals),
1310
+ currentPrice: price?.price ?? null,
1311
+ currentValue,
1312
+ actualWeightBps: null,
1313
+ // computed after totals
1314
+ driftBps: null,
1315
+ pnl: currentValue !== null ? currentValue - investedNum : null,
1316
+ pnlPct: currentValue !== null && investedNum > 0 ? (currentValue - investedNum) / investedNum * 100 : null
1317
+ };
1318
+ });
1319
+ let maxDriftBps = 0;
1320
+ let maxDriftToken = "";
1321
+ if (pricesAvailable && totalPortfolioValue > 0) {
1322
+ for (const a of allocStatuses) {
1323
+ if (a.currentValue !== null) {
1324
+ a.actualWeightBps = Math.round(a.currentValue / totalPortfolioValue * 1e4);
1325
+ a.driftBps = a.actualWeightBps - a.targetWeightBps;
1326
+ if (Math.abs(a.driftBps) > Math.abs(maxDriftBps)) {
1327
+ maxDriftBps = a.driftBps;
1328
+ maxDriftToken = a.symbol;
1329
+ }
1330
+ }
1331
+ }
1332
+ }
1333
+ const totalInvestedNum = Number(formatUnits(totalInvested, assetDecimals));
1334
+ const totalPnl = pricesAvailable ? totalPortfolioValue - totalInvestedNum : null;
1335
+ const totalPnlPct = totalPnl !== null && totalInvestedNum > 0 ? totalPnl / totalInvestedNum * 100 : null;
1336
+ spinner?.succeed("Strategy state loaded");
1337
+ if (jsonMode) {
1338
+ const result = {
1339
+ clone,
1340
+ vault,
1341
+ proposer,
1342
+ state: stateStr,
1343
+ network,
1344
+ asset: { address: assetAddr, symbol: assetSymbol, decimals: assetDecimals },
1345
+ totalDeployed: formatUnits(totalAmount, assetDecimals),
1346
+ maxSlippageBps: Number(maxSlippage),
1347
+ assetBalance: formatUnits(assetBalance, assetDecimals),
1348
+ pricesAvailable,
1349
+ priceSource,
1350
+ portfolio: {
1351
+ totalValue: pricesAvailable ? totalPortfolioValue : null,
1352
+ totalPnl,
1353
+ totalPnlPct
1354
+ },
1355
+ allocations: allocStatuses,
1356
+ maxDriftBps: pricesAvailable ? maxDriftBps : null,
1357
+ maxDriftToken: pricesAvailable ? maxDriftToken : null,
1358
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1359
+ };
1360
+ process.stdout.write(JSON.stringify(result) + "\n");
1361
+ return;
1362
+ }
1363
+ const stateColor = stateStr === "Executed" ? chalk.green : stateStr === "Settled" ? chalk.blue : chalk.yellow;
1364
+ console.log();
1365
+ console.log(chalk.bold("Portfolio Strategy Status"));
1366
+ console.log(chalk.dim("\u2500".repeat(70)));
1367
+ console.log(` Clone: ${chalk.cyan(clone)}`);
1368
+ console.log(` Vault: ${chalk.cyan(vault)}`);
1369
+ console.log(` Proposer: ${chalk.cyan(proposer)}`);
1370
+ console.log(` State: ${stateColor(stateStr)}`);
1371
+ console.log(` Asset: ${assetSymbol} (${assetAddr})`);
1372
+ console.log(` Deployed: ${formatUnits(totalAmount, assetDecimals)} ${assetSymbol}`);
1373
+ console.log(` Max Slip: ${Number(maxSlippage) / 100}%`);
1374
+ console.log(` Asset held: ${formatUnits(assetBalance, assetDecimals)} ${assetSymbol}`);
1375
+ if (pricesAvailable) {
1376
+ const pvStr = totalPortfolioValue.toFixed(6);
1377
+ const pnlStr = totalPnl !== null ? (totalPnl >= 0 ? "+" : "") + totalPnl.toFixed(6) : "n/a";
1378
+ const pnlPctStr = totalPnlPct !== null ? (totalPnlPct >= 0 ? "+" : "") + totalPnlPct.toFixed(1) + "%" : "";
1379
+ const pnlColor = totalPnl !== null && totalPnl >= 0 ? chalk.green : chalk.red;
1380
+ console.log(` Value: ${pvStr} ${assetSymbol} | PnL: ${pnlColor(`${pnlStr} (${pnlPctStr})`)}`);
1381
+ console.log(` Price src: ${priceSource}`);
1382
+ }
1383
+ console.log();
1384
+ console.log(chalk.bold("Allocations"));
1385
+ console.log(chalk.dim("\u2500".repeat(70)));
1386
+ if (pricesAvailable) {
1387
+ console.log(
1388
+ chalk.dim(" Token".padEnd(10)) + chalk.dim("Target".padEnd(9)) + chalk.dim("Actual".padEnd(9)) + chalk.dim("Drift".padEnd(8)) + chalk.dim("Value".padEnd(16)) + chalk.dim("PnL".padEnd(16)) + chalk.dim("Balance")
1389
+ );
1390
+ for (const a of allocStatuses) {
1391
+ const targetStr = (a.targetWeightBps / 100).toFixed(1) + "%";
1392
+ const actualStr = a.actualWeightBps !== null ? (a.actualWeightBps / 100).toFixed(1) + "%" : "\u2014";
1393
+ const driftStr = a.driftBps !== null ? (a.driftBps >= 0 ? "+" : "") + a.driftBps : "\u2014";
1394
+ const driftColor = a.driftBps !== null ? Math.abs(a.driftBps) > 500 ? chalk.red : Math.abs(a.driftBps) > 200 ? chalk.yellow : chalk.dim : chalk.dim;
1395
+ const valueStr = a.currentValue !== null ? a.currentValue.toFixed(6) : "\u2014";
1396
+ const pnlPctStr = a.pnlPct !== null ? (a.pnlPct >= 0 ? "+" : "") + a.pnlPct.toFixed(1) + "%" : "\u2014";
1397
+ const pnlColor = a.pnlPct !== null ? a.pnlPct >= 0 ? chalk.green : chalk.red : chalk.dim;
1398
+ console.log(
1399
+ ` ${chalk.bold(a.symbol.padEnd(8))}${targetStr.padEnd(9)}${actualStr.padEnd(9)}${driftColor(driftStr.toString().padEnd(8))}${valueStr.padEnd(16)}${pnlColor(pnlPctStr.padEnd(16))}${a.balance}`
1400
+ );
1401
+ }
1402
+ } else {
1403
+ console.log(chalk.dim(" Prices unavailable \u2014 showing raw balances only."));
1404
+ console.log();
1405
+ console.log(
1406
+ chalk.dim(" Token".padEnd(12)) + chalk.dim("Weight".padEnd(10)) + chalk.dim("Invested".padEnd(18)) + chalk.dim("Balance".padEnd(18)) + chalk.dim("Address")
1407
+ );
1408
+ for (const a of allocStatuses) {
1409
+ const weightPct = (a.targetWeightBps / 100).toFixed(1) + "%";
1410
+ console.log(
1411
+ ` ${chalk.bold(a.symbol.padEnd(10))}${weightPct.padEnd(10)}${a.investedAmount.padEnd(18)}${a.balance.padEnd(18)}${chalk.dim(a.token)}`
1412
+ );
1413
+ }
1414
+ }
1415
+ console.log(chalk.dim("\u2500".repeat(70)));
1416
+ console.log(` Total invested: ${formatUnits(totalInvested, assetDecimals)} ${assetSymbol}`);
1417
+ if (pricesAvailable && maxDriftToken) {
1418
+ const absMaxDrift = Math.abs(maxDriftBps);
1419
+ const driftColor = absMaxDrift > 500 ? chalk.red : absMaxDrift > 200 ? chalk.yellow : chalk.green;
1420
+ console.log(` Max drift: ${driftColor(`${maxDriftBps > 0 ? "+" : ""}${maxDriftBps} bps`)} (${maxDriftToken})`);
1421
+ }
1422
+ if (stateStr === "Executed") {
1423
+ console.log();
1424
+ console.log(chalk.dim("Rebalance: sherwood strategy rebalance " + clone));
1425
+ console.log(chalk.dim("With new weights: sherwood strategy rebalance " + clone + " --new-weights 2500,2500,2000,1500,1500"));
1426
+ }
1427
+ console.log();
1428
+ } catch (err) {
1429
+ spinner?.fail("Failed to read strategy state");
1430
+ console.error(chalk.red(formatContractError(err)));
1431
+ process.exit(1);
1432
+ }
1433
+ });
1434
+ strategy2.command("rebalance").description("Rebalance a portfolio strategy \u2014 sell all positions, re-buy at target weights (Portfolio only)").argument("<clone>", "Strategy clone address").option("--new-weights <list>", "Comma-separated new weights in bps (must sum to 10000). Updates weights before rebalancing.").option("--max-slippage <bps>", "New max slippage bps (used with --new-weights)").option("--dry-run", "Show what would happen without executing").action(async (cloneArg, opts) => {
1435
+ if (!isAddress(cloneArg)) {
1436
+ console.error(chalk.red("Invalid clone address"));
1437
+ process.exit(1);
1438
+ }
1439
+ const clone = cloneArg;
1440
+ const publicClient = getPublicClient();
1441
+ const account = getAccount();
1442
+ const chain = getChain();
1443
+ const verifySpinner = ora("Verifying strategy state...").start();
1444
+ try {
1445
+ const [stateRaw, proposer, assetAddr, allocations] = await Promise.all([
1446
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "state" }),
1447
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "proposer" }),
1448
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "asset" }),
1449
+ publicClient.readContract({ address: clone, abi: PORTFOLIO_STRATEGY_ABI, functionName: "getAllocations" })
1450
+ ]);
1451
+ if (Number(stateRaw) !== 1) {
1452
+ const stateNames = ["Pending", "Executed", "Settled"];
1453
+ verifySpinner.fail(`Strategy is ${stateNames[Number(stateRaw)] || "Unknown"}, must be Executed to rebalance`);
1454
+ process.exit(1);
1455
+ }
1456
+ if (proposer.toLowerCase() !== account.address.toLowerCase()) {
1457
+ verifySpinner.fail(`Only the proposer (${proposer}) can rebalance. Your wallet: ${account.address}`);
1458
+ process.exit(1);
1459
+ }
1460
+ const [assetDecimals, assetSymbol] = await Promise.all([
1461
+ publicClient.readContract({ address: assetAddr, abi: erc20Abi, functionName: "decimals" }),
1462
+ publicClient.readContract({ address: assetAddr, abi: erc20Abi, functionName: "symbol" })
1463
+ ]);
1464
+ const tokenReads = allocations.map((a) => Promise.all([
1465
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "balanceOf", args: [clone] }),
1466
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "symbol" }),
1467
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "decimals" })
1468
+ ]));
1469
+ const tokenData = await Promise.all(tokenReads);
1470
+ verifySpinner.succeed("Strategy is Executed \u2014 ready to rebalance");
1471
+ console.log();
1472
+ console.log(chalk.bold("Current Allocations"));
1473
+ console.log(chalk.dim("\u2500".repeat(50)));
1474
+ for (let i = 0; i < allocations.length; i++) {
1475
+ const alloc = allocations[i];
1476
+ const [balance, symbol, decimals] = tokenData[i];
1477
+ const weightPct = (Number(alloc.targetWeightBps) / 100).toFixed(1) + "%";
1478
+ console.log(
1479
+ ` ${chalk.bold(symbol.padEnd(8))} ${weightPct.padEnd(8)} bal: ${formatUnits(balance, decimals)}`
1480
+ );
1481
+ }
1482
+ let newWeightsBps;
1483
+ if (opts.newWeights) {
1484
+ newWeightsBps = opts.newWeights.split(",").map((w) => Number(w.trim()));
1485
+ if (newWeightsBps.length !== allocations.length) {
1486
+ console.error(chalk.red(`--new-weights must have ${allocations.length} values (one per token)`));
1487
+ process.exit(1);
1488
+ }
1489
+ const weightSum = newWeightsBps.reduce((a, b) => a + b, 0);
1490
+ if (weightSum !== 1e4) {
1491
+ console.error(chalk.red(`Weights must sum to 10000, got ${weightSum}`));
1492
+ process.exit(1);
1493
+ }
1494
+ console.log();
1495
+ console.log(chalk.bold("New Target Weights"));
1496
+ console.log(chalk.dim("\u2500".repeat(50)));
1497
+ for (let i = 0; i < allocations.length; i++) {
1498
+ const [, symbol] = tokenData[i];
1499
+ const oldPct = (Number(allocations[i].targetWeightBps) / 100).toFixed(1);
1500
+ const newPct = (newWeightsBps[i] / 100).toFixed(1);
1501
+ const arrow = oldPct !== newPct ? chalk.yellow("\u2192") : chalk.dim("\u2192");
1502
+ console.log(` ${chalk.bold(symbol.padEnd(8))} ${oldPct}% ${arrow} ${newPct}%`);
1503
+ }
1504
+ }
1505
+ if (opts.dryRun) {
1506
+ console.log();
1507
+ console.log(chalk.yellow("Dry run \u2014 no transactions sent."));
1508
+ console.log(chalk.dim("The rebalance would:"));
1509
+ console.log(chalk.dim(" 1. Sell all current token positions back to " + assetSymbol));
1510
+ console.log(chalk.dim(" 2. Re-buy at " + (newWeightsBps ? "new" : "current") + " target weights"));
1511
+ console.log();
1512
+ return;
1513
+ }
1514
+ if (newWeightsBps) {
1515
+ const maxSlip = Number(opts.maxSlippage || "0");
1516
+ const swapData = await publicClient.readContract({
1517
+ address: clone,
1518
+ abi: PORTFOLIO_STRATEGY_ABI,
1519
+ functionName: "getSwapExtraData"
1520
+ });
1521
+ const updateSpinner = ora("Updating target weights...").start();
1522
+ try {
1523
+ const innerData = encodeAbiParameters7(
1524
+ [{ type: "uint256[]" }, { type: "uint256" }, { type: "bytes[]" }],
1525
+ [newWeightsBps.map((w) => BigInt(w)), BigInt(maxSlip), swapData]
1526
+ );
1527
+ const updateHash = await writeContractWithRetry({
1528
+ account,
1529
+ chain,
1530
+ address: clone,
1531
+ abi: PORTFOLIO_STRATEGY_ABI,
1532
+ functionName: "updateParams",
1533
+ args: [innerData]
1534
+ });
1535
+ const receipt = await waitForReceipt(updateHash);
1536
+ if (receipt.status === "reverted") throw new Error("updateParams reverted");
1537
+ updateSpinner.succeed("Target weights updated");
1538
+ console.log(chalk.dim(` Tx: ${getExplorerUrl(updateHash)}`));
1539
+ } catch (err) {
1540
+ updateSpinner.fail("Failed to update weights");
1541
+ console.error(chalk.red(formatContractError(err)));
1542
+ process.exit(1);
1543
+ }
1544
+ }
1545
+ const rebalanceSpinner = ora("Rebalancing portfolio (sell all \u2192 re-buy at targets)...").start();
1546
+ try {
1547
+ const rebalanceHash = await writeContractWithRetry({
1548
+ account,
1549
+ chain,
1550
+ address: clone,
1551
+ abi: PORTFOLIO_STRATEGY_ABI,
1552
+ functionName: "rebalance"
1553
+ });
1554
+ const receipt = await waitForReceipt(rebalanceHash);
1555
+ if (receipt.status === "reverted") throw new Error("rebalance() reverted on-chain");
1556
+ rebalanceSpinner.succeed("Portfolio rebalanced");
1557
+ console.log(chalk.dim(` Tx: ${getExplorerUrl(rebalanceHash)}`));
1558
+ } catch (err) {
1559
+ rebalanceSpinner.fail("Rebalance failed");
1560
+ console.error(chalk.red(formatContractError(err)));
1561
+ process.exit(1);
1562
+ }
1563
+ const postSpinner = ora("Reading updated allocations...").start();
1564
+ const postAllocations = await publicClient.readContract({
1565
+ address: clone,
1566
+ abi: PORTFOLIO_STRATEGY_ABI,
1567
+ functionName: "getAllocations"
1568
+ });
1569
+ const postReads = postAllocations.map((a) => Promise.all([
1570
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "balanceOf", args: [clone] }),
1571
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "symbol" }),
1572
+ publicClient.readContract({ address: a.token, abi: erc20Abi, functionName: "decimals" })
1573
+ ]));
1574
+ const postData = await Promise.all(postReads);
1575
+ postSpinner.succeed("Updated allocations");
1576
+ console.log();
1577
+ console.log(chalk.bold("Post-Rebalance Allocations"));
1578
+ console.log(chalk.dim("\u2500".repeat(50)));
1579
+ for (let i = 0; i < postAllocations.length; i++) {
1580
+ const alloc = postAllocations[i];
1581
+ const [balance, symbol, decimals] = postData[i];
1582
+ const weightPct = (Number(alloc.targetWeightBps) / 100).toFixed(1) + "%";
1583
+ const investedStr = formatUnits(alloc.investedAmount, assetDecimals);
1584
+ console.log(
1585
+ ` ${chalk.bold(symbol.padEnd(8))} ${weightPct.padEnd(8)} invested: ${investedStr.padEnd(14)} bal: ${formatUnits(balance, decimals)}`
1586
+ );
1587
+ }
1588
+ console.log();
1589
+ console.log(chalk.green("\u2713 Rebalance complete"));
1590
+ console.log();
1591
+ } catch (err) {
1592
+ if (err.code === "ERR_MODULE_NOT_FOUND" || err instanceof TypeError) throw err;
1593
+ verifySpinner.fail("Pre-flight check failed");
1594
+ console.error(chalk.red(formatContractError(err)));
1595
+ process.exit(1);
1596
+ }
1597
+ });
1066
1598
  }
1067
1599
 
1068
1600
  // src/lib/factory.ts
@@ -1250,7 +1782,7 @@ async function getActiveSyndicates2(creator) {
1250
1782
  }
1251
1783
 
1252
1784
  // src/commands/venice.ts
1253
- import { formatUnits as formatUnits2, isAddress as isAddress2 } from "viem";
1785
+ import { formatUnits as formatUnits3, isAddress as isAddress2 } from "viem";
1254
1786
  import chalk2 from "chalk";
1255
1787
  import ora2 from "ora";
1256
1788
  import { readFileSync } from "fs";
@@ -1273,7 +1805,7 @@ function registerVeniceCommands(program2) {
1273
1805
  console.log(chalk2.yellow(" Use the VeniceInferenceStrategy via a proposal to distribute sVVV to agents."));
1274
1806
  process.exit(1);
1275
1807
  }
1276
- checkSpinner.succeed(`sVVV balance: ${formatUnits2(sVvvBalance, 18)}`);
1808
+ checkSpinner.succeed(`sVVV balance: ${formatUnits3(sVvvBalance, 18)}`);
1277
1809
  } catch (err) {
1278
1810
  checkSpinner.fail("Failed to check sVVV balance");
1279
1811
  console.error(chalk2.red(formatContractError(err)));
@@ -1286,7 +1818,7 @@ function registerVeniceCommands(program2) {
1286
1818
  console.log(chalk2.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
1287
1819
  console.log(chalk2.dim(" Saved to ~/.sherwood/config.json"));
1288
1820
  try {
1289
- const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-X5UIEM6D.js");
1821
+ const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-ZMTIOZH6.js");
1290
1822
  const { uid } = await createVeniceProvisionAttestation(account.address);
1291
1823
  if (uid !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
1292
1824
  console.log(chalk2.dim(` Attested: ${getEasScanUrl2(uid)}`));
@@ -1358,17 +1890,17 @@ function registerVeniceCommands(program2) {
1358
1890
  console.log(chalk2.bold("Venice Inference Status"));
1359
1891
  console.log(chalk2.dim("\u2500".repeat(50)));
1360
1892
  console.log(chalk2.bold("\n Vault"));
1361
- console.log(` Profit available: ${formatUnits2(profit, assetDecimals)} ${assetSymbol}`);
1362
- console.log(` VVV (unstaked): ${formatUnits2(vaultVvvBalance, 18)}`);
1893
+ console.log(` Profit available: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
1894
+ console.log(` VVV (unstaked): ${formatUnits3(vaultVvvBalance, 18)}`);
1363
1895
  console.log(chalk2.bold("\n Agent sVVV Balances"));
1364
1896
  for (const { agent, balance } of agentBalances) {
1365
1897
  const isMe = agent.toLowerCase() === account.address.toLowerCase();
1366
1898
  const label = isMe ? chalk2.green(`${agent} (you)`) : agent;
1367
- console.log(` ${label}: ${formatUnits2(balance, 18)} sVVV`);
1899
+ console.log(` ${label}: ${formatUnits3(balance, 18)} sVVV`);
1368
1900
  }
1369
1901
  console.log(chalk2.bold("\n Your Wallet"));
1370
- console.log(` sVVV: ${formatUnits2(mySvvv, 18)}`);
1371
- console.log(` Pending rewards: ${formatUnits2(myPending, 18)} VVV`);
1902
+ console.log(` sVVV: ${formatUnits3(mySvvv, 18)}`);
1903
+ console.log(` Pending rewards: ${formatUnits3(myPending, 18)} VVV`);
1372
1904
  console.log(chalk2.bold("\n Venice API"));
1373
1905
  console.log(` Key: ${apiKey ? `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}` : chalk2.dim("not provisioned")}`);
1374
1906
  console.log(` Status: ${apiKeyValid ? chalk2.green("valid") : chalk2.red("invalid/missing")}`);
@@ -1437,10 +1969,10 @@ ${opts.prompt}`;
1437
1969
  console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
1438
1970
  }
1439
1971
  try {
1440
- const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-X5UIEM6D.js");
1972
+ const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-ZMTIOZH6.js");
1441
1973
  const { keccak256, toHex, isAddress: isAddr } = await import("viem");
1442
- const { getChainContracts: getChainContracts2 } = await import("./config-BGS5MX4D.js");
1443
- const { getChain: getActiveChain } = await import("./network-UTSOP7EF.js");
1974
+ const { getChainContracts: getChainContracts2 } = await import("./config-EHCEKT2B.js");
1975
+ const { getChain: getActiveChain } = await import("./network-UVMYTKQX.js");
1444
1976
  const vaultRecipient = opts.vault && isAddr(opts.vault) ? opts.vault : getChainContracts2(getActiveChain().id).vault;
1445
1977
  const promptHash = keccak256(toHex(userContent)).slice(0, 18);
1446
1978
  const { uid } = await createVeniceInferenceAttestation(
@@ -1464,12 +1996,12 @@ ${opts.prompt}`;
1464
1996
  }
1465
1997
 
1466
1998
  // src/commands/allowance.ts
1467
- import { parseUnits as parseUnits4, formatUnits as formatUnits3, isAddress as isAddress3 } from "viem";
1999
+ import { parseUnits as parseUnits4, formatUnits as formatUnits4, isAddress as isAddress3 } from "viem";
1468
2000
  import chalk3 from "chalk";
1469
2001
  import ora3 from "ora";
1470
2002
 
1471
2003
  // src/strategies/allowance-disburse.ts
1472
- import { encodeFunctionData as encodeFunctionData6, parseUnits as parseUnits3 } from "viem";
2004
+ import { encodeFunctionData as encodeFunctionData7, parseUnits as parseUnits3 } from "viem";
1473
2005
  function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minUsdc, swapPath) {
1474
2006
  const assetAmount = parseUnits3(config.amount, assetDecimals);
1475
2007
  const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
@@ -1478,7 +2010,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1478
2010
  if (!isUsdc) {
1479
2011
  calls.push({
1480
2012
  target: assetAddress,
1481
- data: encodeFunctionData6({
2013
+ data: encodeFunctionData7({
1482
2014
  abi: ERC20_ABI,
1483
2015
  functionName: "approve",
1484
2016
  args: [UNISWAP().SWAP_ROUTER, assetAmount]
@@ -1488,7 +2020,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1488
2020
  if (isWeth) {
1489
2021
  calls.push({
1490
2022
  target: UNISWAP().SWAP_ROUTER,
1491
- data: encodeFunctionData6({
2023
+ data: encodeFunctionData7({
1492
2024
  abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
1493
2025
  functionName: "exactInputSingle",
1494
2026
  args: [
@@ -1508,7 +2040,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1508
2040
  } else {
1509
2041
  calls.push({
1510
2042
  target: UNISWAP().SWAP_ROUTER,
1511
- data: encodeFunctionData6({
2043
+ data: encodeFunctionData7({
1512
2044
  abi: SWAP_ROUTER_ABI,
1513
2045
  functionName: "exactInput",
1514
2046
  args: [
@@ -1528,7 +2060,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
1528
2060
  for (const agent of agents) {
1529
2061
  calls.push({
1530
2062
  target: TOKENS().USDC,
1531
- data: encodeFunctionData6({
2063
+ data: encodeFunctionData7({
1532
2064
  abi: ERC20_ABI,
1533
2065
  functionName: "transfer",
1534
2066
  args: [agent, perAgent]
@@ -1593,9 +2125,9 @@ function registerAllowanceCommands(program2) {
1593
2125
  console.log(chalk3.dim("\u2500".repeat(40)));
1594
2126
  console.log(` Asset: ${assetSymbol} (${assetDecimals} decimals)`);
1595
2127
  console.log(` Amount: ${opts.amount} ${assetSymbol}`);
1596
- console.log(` Vault balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
1597
- console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
1598
- console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
2128
+ console.log(` Vault balance: ${formatUnits4(assetBalance, assetDecimals)} ${assetSymbol}`);
2129
+ console.log(` Deposited: ${formatUnits4(totalDeposited, assetDecimals)} ${assetSymbol}`);
2130
+ console.log(` Profit: ${formatUnits4(profit, assetDecimals)} ${assetSymbol}`);
1599
2131
  console.log(` Agents: ${agents.length} (USDC will be split equally)`);
1600
2132
  if (!isUsdc) {
1601
2133
  console.log(` Routing: ${isWeth ? `WETH \u2192 USDC (fee ${fee})` : `${assetSymbol} \u2192 WETH \u2192 USDC (fee ${fee})`}`);
@@ -1604,7 +2136,7 @@ function registerAllowanceCommands(program2) {
1604
2136
  console.log(` Vault: ${vaultAddress}`);
1605
2137
  console.log();
1606
2138
  if (requestedAmount > profit) {
1607
- console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits3(profit, assetDecimals)})`));
2139
+ console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits4(profit, assetDecimals)})`));
1608
2140
  console.warn(chalk3.yellow(" This will use deposited capital, not just profits."));
1609
2141
  console.log();
1610
2142
  }
@@ -1638,7 +2170,7 @@ function registerAllowanceCommands(program2) {
1638
2170
  }
1639
2171
  minUsdc = applySlippage(amountOut, slippageBps);
1640
2172
  quoteSpinner.succeed(
1641
- `Quote: ${formatUnits3(amountOut, 6)} USDC (min: ${formatUnits3(minUsdc, 6)}, per agent: ${formatUnits3(minUsdc / BigInt(agents.length), 6)})`
2173
+ `Quote: ${formatUnits4(amountOut, 6)} USDC (min: ${formatUnits4(minUsdc, 6)}, per agent: ${formatUnits4(minUsdc / BigInt(agents.length), 6)})`
1642
2174
  );
1643
2175
  } catch (err) {
1644
2176
  quoteSpinner.fail("Failed to fetch quote");
@@ -1648,7 +2180,7 @@ function registerAllowanceCommands(program2) {
1648
2180
  }
1649
2181
  const perAgent = minUsdc / BigInt(agents.length);
1650
2182
  if (isUsdc) {
1651
- console.log(chalk3.dim(` Per agent: ${formatUnits3(perAgent, 6)} USDC`));
2183
+ console.log(chalk3.dim(` Per agent: ${formatUnits4(perAgent, 6)} USDC`));
1652
2184
  console.log();
1653
2185
  }
1654
2186
  const config = {
@@ -1715,14 +2247,14 @@ function registerAllowanceCommands(program2) {
1715
2247
  console.log(chalk3.dim("\u2500".repeat(50)));
1716
2248
  console.log(chalk3.bold("\n Vault"));
1717
2249
  console.log(` Asset: ${assetSymbol}`);
1718
- console.log(` Balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
1719
- console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
1720
- console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
2250
+ console.log(` Balance: ${formatUnits4(assetBalance, assetDecimals)} ${assetSymbol}`);
2251
+ console.log(` Deposited: ${formatUnits4(totalDeposited, assetDecimals)} ${assetSymbol}`);
2252
+ console.log(` Profit: ${formatUnits4(profit, assetDecimals)} ${assetSymbol}`);
1721
2253
  console.log(chalk3.bold("\n Agent USDC Balances"));
1722
2254
  for (const { agent, balance } of agentBalances) {
1723
2255
  const isMe = agent.toLowerCase() === account.address.toLowerCase();
1724
2256
  const label = isMe ? chalk3.green(`${agent} (you)`) : agent;
1725
- console.log(` ${label}: ${formatUnits3(balance, 6)} USDC`);
2257
+ console.log(` ${label}: ${formatUnits4(balance, 6)} USDC`);
1726
2258
  }
1727
2259
  console.log();
1728
2260
  } catch (err) {
@@ -1927,7 +2459,7 @@ function parseBigIntArg(value, name) {
1927
2459
  }
1928
2460
 
1929
2461
  // src/lib/simulate.ts
1930
- import { decodeFunctionData, encodeFunctionData as encodeFunctionData7 } from "viem";
2462
+ import { decodeFunctionData, encodeFunctionData as encodeFunctionData8 } from "viem";
1931
2463
  import chalk5 from "chalk";
1932
2464
  var G = chalk5.green;
1933
2465
  var W = chalk5.white;
@@ -2446,7 +2978,7 @@ async function simulateViaApi(vault, calls) {
2446
2978
  async function simulateViaEthCall(vault, calls) {
2447
2979
  const governor = getGovernorAddress();
2448
2980
  const client = getPublicClient();
2449
- const input2 = encodeFunctionData7({
2981
+ const input2 = encodeFunctionData8({
2450
2982
  abi: SYNDICATE_VAULT_ABI,
2451
2983
  functionName: "executeGovernorBatch",
2452
2984
  args: [calls.map((c) => ({ target: c.target, data: c.data, value: c.value }))]
@@ -2569,8 +3101,8 @@ function printSimulationResult(result, callType) {
2569
3101
  }
2570
3102
  async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
2571
3103
  try {
2572
- const xmtp = await import("./xmtp-XKHXATPQ.js");
2573
- const { getAccount: getAccount2 } = await import("./client-SCIY6SUP.js");
3104
+ const xmtp = await import("./xmtp-B2XFVPIV.js");
3105
+ const { getAccount: getAccount2 } = await import("./client-XG6LL6TS.js");
2574
3106
  const group = await xmtp.getGroup("", subdomain);
2575
3107
  const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
2576
3108
  const criticals = allRisks.filter((r) => r.level === "critical");
@@ -3262,7 +3794,7 @@ try {
3262
3794
  var require2 = createRequire(import.meta.url);
3263
3795
  var { version: CLI_VERSION } = require2("../package.json");
3264
3796
  async function loadXmtp() {
3265
- return import("./xmtp-XKHXATPQ.js");
3797
+ return import("./xmtp-B2XFVPIV.js");
3266
3798
  }
3267
3799
  async function loadCron() {
3268
3800
  return import("./cron-EOULYO3R.js");
@@ -3508,8 +4040,11 @@ syndicate.command("create").description("Create a new syndicate via the factory
3508
4040
  const xmtp = await loadXmtp();
3509
4041
  const xmtpClient = await xmtp.getXmtpClient();
3510
4042
  const groupId = await xmtp.createSyndicateGroup(xmtpClient, subdomain, opts.publicChat);
3511
- await setTextRecord(subdomain, "xmtpGroupId", groupId, result.vault);
3512
4043
  cacheGroupId(subdomain, groupId);
4044
+ try {
4045
+ await setTextRecord(subdomain, "xmtpGroupId", groupId, result.vault);
4046
+ } catch {
4047
+ }
3513
4048
  } catch {
3514
4049
  console.warn(chalk8.yellow("\n \u26A0 Could not create XMTP chat group"));
3515
4050
  console.warn(chalk8.dim(` Recover later with: sherwood chat ${subdomain} init`));
@@ -4222,7 +4757,7 @@ vaultCmd.command("balance").description("Show LP share balance and asset value")
4222
4757
  var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
4223
4758
  registerStrategyTemplateCommands(strategy);
4224
4759
  program.command("providers").description("List available DeFi providers").action(async () => {
4225
- const { MessariProvider, NansenProvider } = await import("./research-SJ6D3L2B.js");
4760
+ const { MessariProvider, NansenProvider } = await import("./research-2I6AA3BI.js");
4226
4761
  const providers = [new MoonwellProvider(), new UniswapProvider(), new MessariProvider(), new NansenProvider()];
4227
4762
  for (const p of providers) {
4228
4763
  const info = p.info();
@@ -4233,7 +4768,7 @@ ${info.name} (${info.type})`);
4233
4768
  }
4234
4769
  });
4235
4770
  try {
4236
- const { registerChatCommands } = await import("./chat-JYAJMP4D.js");
4771
+ const { registerChatCommands } = await import("./chat-3SAX4VRO.js");
4237
4772
  registerChatCommands(program);
4238
4773
  } catch {
4239
4774
  program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
@@ -4243,16 +4778,16 @@ try {
4243
4778
  process.exit(1);
4244
4779
  });
4245
4780
  }
4246
- var { registerSessionCommands } = await import("./session-XZNKLK3I.js");
4781
+ var { registerSessionCommands } = await import("./session-2FIR4LJP.js");
4247
4782
  registerSessionCommands(program);
4248
4783
  registerVeniceCommands(program);
4249
4784
  registerAllowanceCommands(program);
4250
4785
  registerIdentityCommands(program);
4251
4786
  registerProposalCommands(program);
4252
4787
  registerGovernorCommands(program);
4253
- var { registerResearchCommands } = await import("./research-ZW6XVTGZ.js");
4788
+ var { registerResearchCommands } = await import("./research-KUIZM6AK.js");
4254
4789
  registerResearchCommands(program);
4255
- var { registerTradeCommands } = await import("./trade-OJM5HNHL.js");
4790
+ var { registerTradeCommands } = await import("./trade-UTM3DSO3.js");
4256
4791
  registerTradeCommands(program);
4257
4792
  var configCmd = program.command("config");
4258
4793
  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.)").option("--uniswap-api-key <key>", "Uniswap Trading API key (from developers.uniswap.org)").option("--venice-api-key <key>", "Venice AI inference API key").action((opts) => {