@sherwoodagent/cli 0.86.1 → 0.87.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 (71) hide show
  1. package/dist/{abis-WVW2EBI3.js → abis-WJQ6IVYV.js} +2 -2
  2. package/dist/{agent-TBLC3WNJ.js → agent-A2JEYGQS.js} +7 -7
  3. package/dist/{chat-ETZSKQDI.js → chat-OZAAN5LT.js} +8 -8
  4. package/dist/{chunk-ZN2MHIB7.js → chunk-37GT3TJX.js} +5 -5
  5. package/dist/{chunk-45FELUWY.js → chunk-3UYGXGMF.js} +2 -2
  6. package/dist/{chunk-YAS52NEF.js → chunk-CU42ZD4K.js} +5 -5
  7. package/dist/chunk-CU42ZD4K.js.map +1 -0
  8. package/dist/{chunk-PVTZMRC6.js → chunk-G3FUEM5N.js} +2 -2
  9. package/dist/chunk-G3FUEM5N.js.map +1 -0
  10. package/dist/{chunk-XPVXNG2K.js → chunk-GR3GSU3I.js} +6 -6
  11. package/dist/{chunk-KVB5P2OE.js → chunk-IINWI3LD.js} +2 -2
  12. package/dist/{chunk-F3MDCUGO.js → chunk-J2IZWAEW.js} +75 -227
  13. package/dist/chunk-J2IZWAEW.js.map +1 -0
  14. package/dist/{chunk-3IAZQMAW.js → chunk-JGD6A2Q4.js} +29 -82
  15. package/dist/chunk-JGD6A2Q4.js.map +1 -0
  16. package/dist/{chunk-QRMZRAMG.js → chunk-MIAMGVZ4.js} +8 -8
  17. package/dist/chunk-MIAMGVZ4.js.map +1 -0
  18. package/dist/{chunk-EA65CDQH.js → chunk-R6F57QQF.js} +14 -23
  19. package/dist/chunk-R6F57QQF.js.map +1 -0
  20. package/dist/{chunk-EVUKJ7CJ.js → chunk-TTF5TDRV.js} +5 -5
  21. package/dist/{chunk-IAM4VIU2.js → chunk-UOIAY6ZG.js} +6 -39
  22. package/dist/chunk-UOIAY6ZG.js.map +1 -0
  23. package/dist/{chunk-6QBGTX2Q.js → chunk-V7TNYHIK.js} +257 -484
  24. package/dist/chunk-V7TNYHIK.js.map +1 -0
  25. package/dist/{chunk-OUYMZ5ZC.js → chunk-W3XWRWML.js} +5 -5
  26. package/dist/{client-3SE632Q2.js → client-C6N2ASTH.js} +3 -3
  27. package/dist/{eas-KMDAMLXW.js → eas-VFTWEI4K.js} +6 -6
  28. package/dist/{governor-JNSWPJVQ.js → governor-HVBSI6Z2.js} +6 -6
  29. package/dist/identity-OLD25QEP.js +18 -0
  30. package/dist/index.js +91 -305
  31. package/dist/index.js.map +1 -1
  32. package/dist/{network-FEHRFDPJ.js → network-7445KSCF.js} +2 -2
  33. package/dist/{price-YNPYE2EO.js → price-O3THX2HL.js} +6 -6
  34. package/dist/{providers-BMOHHVUN.js → providers-KZNCCUKT.js} +4 -4
  35. package/dist/{research-W74PNYPO.js → research-ARFBFXIT.js} +7 -7
  36. package/dist/{session-HVRZ6AJM.js → session-A7CYZSSA.js} +14 -12
  37. package/dist/session-A7CYZSSA.js.map +1 -0
  38. package/dist/{trade-EOQY72L7.js → trade-ZCK332E4.js} +15 -15
  39. package/dist/{vault-HWJQJW5U.js → vault-CDI7BELZ.js} +8 -8
  40. package/dist/{xmtp-KW73BGVO.js → xmtp-7LAWDKJT.js} +6 -6
  41. package/package.json +1 -1
  42. package/dist/chunk-3IAZQMAW.js.map +0 -1
  43. package/dist/chunk-6QBGTX2Q.js.map +0 -1
  44. package/dist/chunk-EA65CDQH.js.map +0 -1
  45. package/dist/chunk-F3MDCUGO.js.map +0 -1
  46. package/dist/chunk-IAM4VIU2.js.map +0 -1
  47. package/dist/chunk-PVTZMRC6.js.map +0 -1
  48. package/dist/chunk-QRMZRAMG.js.map +0 -1
  49. package/dist/chunk-YAS52NEF.js.map +0 -1
  50. package/dist/identity-ATWV2O7Y.js +0 -15
  51. package/dist/session-HVRZ6AJM.js.map +0 -1
  52. /package/dist/{abis-WVW2EBI3.js.map → abis-WJQ6IVYV.js.map} +0 -0
  53. /package/dist/{agent-TBLC3WNJ.js.map → agent-A2JEYGQS.js.map} +0 -0
  54. /package/dist/{chat-ETZSKQDI.js.map → chat-OZAAN5LT.js.map} +0 -0
  55. /package/dist/{chunk-ZN2MHIB7.js.map → chunk-37GT3TJX.js.map} +0 -0
  56. /package/dist/{chunk-45FELUWY.js.map → chunk-3UYGXGMF.js.map} +0 -0
  57. /package/dist/{chunk-XPVXNG2K.js.map → chunk-GR3GSU3I.js.map} +0 -0
  58. /package/dist/{chunk-KVB5P2OE.js.map → chunk-IINWI3LD.js.map} +0 -0
  59. /package/dist/{chunk-EVUKJ7CJ.js.map → chunk-TTF5TDRV.js.map} +0 -0
  60. /package/dist/{chunk-OUYMZ5ZC.js.map → chunk-W3XWRWML.js.map} +0 -0
  61. /package/dist/{client-3SE632Q2.js.map → client-C6N2ASTH.js.map} +0 -0
  62. /package/dist/{eas-KMDAMLXW.js.map → eas-VFTWEI4K.js.map} +0 -0
  63. /package/dist/{governor-JNSWPJVQ.js.map → governor-HVBSI6Z2.js.map} +0 -0
  64. /package/dist/{identity-ATWV2O7Y.js.map → identity-OLD25QEP.js.map} +0 -0
  65. /package/dist/{network-FEHRFDPJ.js.map → network-7445KSCF.js.map} +0 -0
  66. /package/dist/{price-YNPYE2EO.js.map → price-O3THX2HL.js.map} +0 -0
  67. /package/dist/{providers-BMOHHVUN.js.map → providers-KZNCCUKT.js.map} +0 -0
  68. /package/dist/{research-W74PNYPO.js.map → research-ARFBFXIT.js.map} +0 -0
  69. /package/dist/{trade-EOQY72L7.js.map → trade-ZCK332E4.js.map} +0 -0
  70. /package/dist/{vault-HWJQJW5U.js.map → vault-CDI7BELZ.js.map} +0 -0
  71. /package/dist/{xmtp-KW73BGVO.js.map → xmtp-7LAWDKJT.js.map} +0 -0
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  checkApiKeyValid,
16
16
  listModels,
17
17
  provisionApiKey
18
- } from "./chunk-KVB5P2OE.js";
18
+ } from "./chunk-IINWI3LD.js";
19
19
  import {
20
20
  DEFAULT_FEE_TIER,
21
21
  HYPERLIQUID_PERP_STRATEGY_ABI,
@@ -31,7 +31,7 @@ import {
31
31
  parseAlignedOverrides,
32
32
  resolveToken,
33
33
  selectBestFeeTier
34
- } from "./chunk-3IAZQMAW.js";
34
+ } from "./chunk-JGD6A2Q4.js";
35
35
  import {
36
36
  DEFAULT_ISSUING_CHAIN_ID,
37
37
  appendVidTag,
@@ -50,7 +50,6 @@ import {
50
50
  encodeMgmtSplit,
51
51
  encodePerfSplit,
52
52
  encodePropose,
53
- encodeProposeWithSandbox,
54
53
  encodeRedeem,
55
54
  encodeRegisterAgent,
56
55
  encodeSettle,
@@ -65,7 +64,7 @@ import {
65
64
  setCalldataOnly,
66
65
  stripVidTag,
67
66
  verifyVidTag
68
- } from "./chunk-6QBGTX2Q.js";
67
+ } from "./chunk-V7TNYHIK.js";
69
68
  import {
70
69
  createApproval,
71
70
  createJoinRequest,
@@ -75,20 +74,20 @@ import {
75
74
  queryJoinRequests,
76
75
  revokeJoinRequest,
77
76
  stripReferrerPrefix
78
- } from "./chunk-OUYMZ5ZC.js";
77
+ } from "./chunk-W3XWRWML.js";
79
78
  import {
80
79
  createFund,
81
80
  getActiveFunds,
82
81
  getFund,
83
82
  subdomainExists,
84
83
  updateMetadata
85
- } from "./chunk-EVUKJ7CJ.js";
84
+ } from "./chunk-TTF5TDRV.js";
86
85
  import {
87
86
  resolveFund,
88
87
  resolveVaultFund,
89
88
  searchFundAcrossChains,
90
89
  setTextRecord
91
- } from "./chunk-ZN2MHIB7.js";
90
+ } from "./chunk-37GT3TJX.js";
92
91
  import {
93
92
  approveDepositor,
94
93
  deposit,
@@ -111,8 +110,8 @@ import {
111
110
  removeDepositor,
112
111
  setAgentFeeBps,
113
112
  setVaultAddress
114
- } from "./chunk-XPVXNG2K.js";
115
- import "./chunk-EA65CDQH.js";
113
+ } from "./chunk-GR3GSU3I.js";
114
+ import "./chunk-R6F57QQF.js";
116
115
  import {
117
116
  PROPOSAL_STATE,
118
117
  PROPOSAL_STATES,
@@ -137,7 +136,6 @@ import {
137
136
  getVoteWeight,
138
137
  hasVoted,
139
138
  parseDuration,
140
- parseProposalIdFromLogs,
141
139
  proposalCount,
142
140
  propose,
143
141
  scanReviewCandidates,
@@ -151,7 +149,7 @@ import {
151
149
  setVotingPeriod,
152
150
  settleProposal,
153
151
  vote
154
- } from "./chunk-YAS52NEF.js";
152
+ } from "./chunk-CU42ZD4K.js";
155
153
  import {
156
154
  AERODROME,
157
155
  MOONWELL,
@@ -160,7 +158,7 @@ import {
160
158
  TOKENS,
161
159
  UNISWAP,
162
160
  VENICE
163
- } from "./chunk-IAM4VIU2.js";
161
+ } from "./chunk-UOIAY6ZG.js";
164
162
  import {
165
163
  GAS_UNITS,
166
164
  estimateGasCushion,
@@ -171,7 +169,7 @@ import {
171
169
  sendTxWithRetry,
172
170
  waitForReceipt,
173
171
  writeContractWithRetry
174
- } from "./chunk-QRMZRAMG.js";
172
+ } from "./chunk-MIAMGVZ4.js";
175
173
  import {
176
174
  DEFAULT_NETWORK,
177
175
  VALID_NETWORKS,
@@ -181,7 +179,7 @@ import {
181
179
  isTestnet,
182
180
  setNetwork,
183
181
  withNetwork
184
- } from "./chunk-PVTZMRC6.js";
182
+ } from "./chunk-G3FUEM5N.js";
185
183
  import {
186
184
  addFund,
187
185
  cacheGroupId,
@@ -214,7 +212,7 @@ import {
214
212
  SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
215
213
  SYNDICATE_VAULT_ABI,
216
214
  VENICE_STAKING_ABI
217
- } from "./chunk-F3MDCUGO.js";
215
+ } from "./chunk-J2IZWAEW.js";
218
216
  import {
219
217
  fetchMetadata,
220
218
  mergeFundMetadata,
@@ -225,13 +223,13 @@ import {
225
223
  import { config as loadDotenv } from "dotenv";
226
224
  import { createRequire } from "module";
227
225
  import { Command, Option } from "commander";
228
- import { parseUnits as parseUnits11, formatUnits as formatUnits9, isAddress as isAddress10 } from "viem";
226
+ import { parseUnits as parseUnits11, formatUnits as formatUnits10, isAddress as isAddress10 } from "viem";
229
227
  import chalk17 from "chalk";
230
228
  import ora9 from "ora";
231
229
  import { input, confirm, select } from "@inquirer/prompts";
232
230
 
233
231
  // src/lib/generated/contract-constants.ts
234
- var MAX_AGENT_FEE_BPS = 3e3;
232
+ var MAX_AGENT_FEE_BPS = 2500;
235
233
 
236
234
  // src/lib/format.ts
237
235
  function formatDurationShort(seconds) {
@@ -892,10 +890,10 @@ function formatBatch(calls) {
892
890
 
893
891
  // src/commands/strategy-propose.ts
894
892
  function registerStrategyProposeCommands(strategy2) {
895
- 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, hyperliquid-perp, hyperliquid-grid").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("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--proposer <address>", "Proposer/agent address (required for --calldata-only \u2014 the external signer)").option("--metadata-uri <uri>", "Metadata URI (required for --calldata-only \u2014 IPFS pin needs a signer)").option("--salt <bytes32>", "CREATE2 salt for the deterministic clone (--calldata-only; default: derived from inputs)").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)").option("--feed-ids <list>", "Comma-separated Chainlink feed ids/addresses per token (Portfolio; auto-resolved from registry in push-feed mode)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8 push / 18 Data Streams)").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
893
+ 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, hyperliquid-perp, hyperliquid-grid").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("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--proposer <address>", "Proposer/agent address (required for --calldata-only \u2014 the external signer)").option("--metadata-uri <uri>", "Metadata URI (required for --calldata-only \u2014 IPFS pin needs a signer)").option("--salt <bytes32>", "CREATE2 salt for the deterministic clone (--calldata-only; default: derived from inputs)").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)").option("--feeds <list>", "Comma-separated Chainlink AggregatorV3 push-feed addresses per token (Portfolio; auto-resolved from the registry when a slot is left empty)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8). Must equal the feed's live decimals().").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
896
894
  "--max-drawdown-bps <bps>",
897
895
  "Declared loss allowance for this proposal, in bps of --amount (0-10000, default 2000 = 20%). This is the envelope voters and guardians are asked to accept, and the basis the settle-price guard sizes its tolerance from \u2014 not a formality."
898
- ).option("--max-price-ages <list>", "Comma-separated per-token max Chainlink push-feed staleness in seconds (Portfolio, push mode; robinhood-mainnet equity feeds default to 345600 = 96h, crypto/stable feeds to the contract default). Empty entry = registry default.").option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
896
+ ).option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
899
897
  const vault = opts.vault;
900
898
  if (!isAddress3(vault)) {
901
899
  console.error(chalk3.red("Invalid vault address"));
@@ -979,7 +977,7 @@ function registerStrategyProposeCommands(strategy2) {
979
977
  process.exit(1);
980
978
  }
981
979
  if (!opts.agent) opts.agent = proposer;
982
- const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-JNSWPJVQ.js");
980
+ const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-HVBSI6Z2.js");
983
981
  const strategyDuration2 = parseDuration3(opts.duration);
984
982
  const chainId = getChain().id;
985
983
  try {
@@ -1210,9 +1208,9 @@ function registerStrategyProposeCommands(strategy2) {
1210
1208
  console.error(chalk3.red("Missing --name or --duration. Use --write-calls to skip proposal submission."));
1211
1209
  process.exit(1);
1212
1210
  }
1213
- const { propose: propose2 } = await import("./governor-JNSWPJVQ.js");
1211
+ const { propose: propose2 } = await import("./governor-HVBSI6Z2.js");
1214
1212
  const { pinJSON } = await import("./ipfs-M56BLMCW.js");
1215
- const { parseDuration: parseDuration2 } = await import("./governor-JNSWPJVQ.js");
1213
+ const { parseDuration: parseDuration2 } = await import("./governor-HVBSI6Z2.js");
1216
1214
  const strategyDuration = parseDuration2(opts.duration);
1217
1215
  const metaSpinner = ora2("Pinning metadata to IPFS...").start();
1218
1216
  let metadataURI;
@@ -1244,7 +1242,7 @@ function registerStrategyProposeCommands(strategy2) {
1244
1242
  metadataURI = `data:application/json;base64,${Buffer.from(inline).toString("base64")}`;
1245
1243
  }
1246
1244
  try {
1247
- const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-HWJQJW5U.js");
1245
+ const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-CDI7BELZ.js");
1248
1246
  const feeBps = await getAgentFeeBps2(vault);
1249
1247
  console.log(
1250
1248
  chalk3.yellow(
@@ -1334,10 +1332,10 @@ function registerStrategyTemplateCommands(strategy2) {
1334
1332
  console.log(chalk4.dim("Full proposal: sherwood strategy propose <template> --vault <addr> ..."));
1335
1333
  console.log();
1336
1334
  });
1337
- 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, hyperliquid-perp, hyperliquid-grid").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)").option("--feed-ids <list>", "Comma-separated Chainlink feed ids/addresses per token (Portfolio; auto-resolved from registry in push-feed mode)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8 push / 18 Data Streams)").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
1335
+ 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, hyperliquid-perp, hyperliquid-grid").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)").option("--feeds <list>", "Comma-separated Chainlink AggregatorV3 push-feed addresses per token (Portfolio; auto-resolved from the registry when a slot is left empty)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8). Must equal the feed's live decimals().").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
1338
1336
  "--max-drawdown-bps <bps>",
1339
1337
  "Declared loss allowance for this proposal, in bps of --amount (0-10000, default 2000 = 20%). This is the envelope voters and guardians are asked to accept, and the basis the settle-price guard sizes its tolerance from \u2014 not a formality."
1340
- ).option("--max-price-ages <list>", "Comma-separated per-token max Chainlink push-feed staleness in seconds (Portfolio, push mode; robinhood-mainnet equity feeds default to 345600 = 96h, crypto/stable feeds to the contract default). Empty entry = registry default.").option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
1338
+ ).option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
1341
1339
  const vault = opts.vault;
1342
1340
  if (!isAddress4(vault)) {
1343
1341
  console.error(chalk4.red("Invalid vault address"));
@@ -1405,10 +1403,10 @@ function registerStrategyTemplateCommands(strategy2) {
1405
1403
  console.log(chalk4.dim("Use this address in your proposal batch calls."));
1406
1404
  console.log();
1407
1405
  });
1408
- 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, hyperliquid-perp, hyperliquid-grid").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)").option("--feed-ids <list>", "Comma-separated Chainlink feed ids/addresses per token (Portfolio; auto-resolved from registry in push-feed mode)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8 push / 18 Data Streams)").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
1406
+ 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, hyperliquid-perp, hyperliquid-grid").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)").option("--feeds <list>", "Comma-separated Chainlink AggregatorV3 push-feed addresses per token (Portfolio; auto-resolved from the registry when a slot is left empty)").option("--price-decimals <list>", "Comma-separated raw feed decimals per token (Portfolio; default 8). Must equal the feed's live decimals().").option("--swap-routes <list>", "Comma-separated per-token swap route spec (Portfolio). Per token: 'v3:<fee>' (mode 0), 'v4:<fee>:<tickSpacing>' (mode 2), or 'v4path:<hop>+<hop>...' (mode 3) where hop='<currency>@<fee>:<tickSpacing>', currency='eth'/'native'=ETH or 'self'=this token or an address. Empty entry = auto-detect / robinhood default.").option(
1409
1407
  "--max-drawdown-bps <bps>",
1410
1408
  "Declared loss allowance for this proposal, in bps of --amount (0-10000, default 2000 = 20%). This is the envelope voters and guardians are asked to accept, and the basis the settle-price guard sizes its tolerance from \u2014 not a formality."
1411
- ).option("--max-price-ages <list>", "Comma-separated per-token max Chainlink push-feed staleness in seconds (Portfolio, push mode; robinhood-mainnet equity feeds default to 345600 = 96h, crypto/stable feeds to the contract default). Empty entry = registry default.").option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
1409
+ ).option("--leverage <number>", "Leverage multiplier (Hyperliquid Perp, default: 10)").option("--asset-index <number>", "Perp asset index (Hyperliquid Perp, default: 0 for BTC)").option("--max-position <amount>", "Max position size in USD (Hyperliquid Perp, default: 100000)").option("--max-trades-per-day <n>", "Max trades per day (Hyperliquid Perp, default: 50)").option("--max-order-size <amount>", "Max single-order size in asset units (Hyperliquid Grid, default: 10000)").option("--max-orders-per-tick <n>", "Max orders per tick (Hyperliquid Grid, default: 20)").option("--asset-indices <list>", "Comma-separated perp asset indices (Hyperliquid Grid, default: 0)").action(async (templateKey, opts) => {
1412
1410
  const clone = opts.clone;
1413
1411
  const vault = opts.vault;
1414
1412
  if (!isAddress4(clone)) {
@@ -1515,7 +1513,7 @@ function registerStrategyTemplateCommands(strategy2) {
1515
1513
  let prices = [];
1516
1514
  let priceSource = null;
1517
1515
  try {
1518
- const { getTokenPricesInAsset } = await import("./price-YNPYE2EO.js");
1516
+ const { getTokenPricesInAsset } = await import("./price-O3THX2HL.js");
1519
1517
  prices = await getTokenPricesInAsset({
1520
1518
  tokens: allocations.map((a, i) => ({
1521
1519
  token: a.token,
@@ -1666,7 +1664,7 @@ function registerStrategyTemplateCommands(strategy2) {
1666
1664
  if (stateStr === "Executed") {
1667
1665
  console.log();
1668
1666
  console.log(chalk4.dim("Rebalance: sherwood strategy rebalance " + clone));
1669
- console.log(chalk4.dim("With new weights: sherwood strategy rebalance " + clone + " --new-weights 2500,2500,2000,1500,1500"));
1667
+ console.log(chalk4.dim("Tighten slippage first: sherwood strategy rebalance " + clone + " --max-slippage 200"));
1670
1668
  }
1671
1669
  console.log();
1672
1670
  } catch (err) {
@@ -1675,7 +1673,7 @@ function registerStrategyTemplateCommands(strategy2) {
1675
1673
  process.exit(1);
1676
1674
  }
1677
1675
  });
1678
- 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) => {
1676
+ strategy2.command("rebalance").description("Rebalance a portfolio strategy \u2014 trade each allocation back to its target weight (Portfolio only)").argument("<clone>", "Strategy clone address").option("--max-slippage <bps>", "Tighten max slippage bps before rebalancing (weights and routes are frozen at init \u2014 only a LOWER tolerance is accepted)").option("--dry-run", "Show what would happen without executing").action(async (cloneArg, opts) => {
1679
1677
  if (!isAddress4(cloneArg)) {
1680
1678
  console.error(chalk4.red("Invalid clone address"));
1681
1679
  process.exit(1);
@@ -1723,50 +1721,29 @@ function registerStrategyTemplateCommands(strategy2) {
1723
1721
  ` ${chalk4.bold(symbol.padEnd(8))} ${weightPct.padEnd(8)} bal: ${formatUnits5(balance, decimals)}`
1724
1722
  );
1725
1723
  }
1726
- let newWeightsBps;
1727
- if (opts.newWeights) {
1728
- newWeightsBps = opts.newWeights.split(",").map((w) => Number(w.trim()));
1729
- if (newWeightsBps.length !== allocations.length) {
1730
- console.error(chalk4.red(`--new-weights must have ${allocations.length} values (one per token)`));
1731
- process.exit(1);
1732
- }
1733
- const weightSum = newWeightsBps.reduce((a, b) => a + b, 0);
1734
- if (weightSum !== 1e4) {
1735
- console.error(chalk4.red(`Weights must sum to 10000, got ${weightSum}`));
1736
- process.exit(1);
1737
- }
1738
- console.log();
1739
- console.log(chalk4.bold("New Target Weights"));
1740
- console.log(chalk4.dim("\u2500".repeat(50)));
1741
- for (let i = 0; i < allocations.length; i++) {
1742
- const [, symbol] = tokenData[i];
1743
- const oldPct = (Number(allocations[i].targetWeightBps) / 100).toFixed(1);
1744
- const newPct = (newWeightsBps[i] / 100).toFixed(1);
1745
- const arrow = oldPct !== newPct ? chalk4.yellow("\u2192") : chalk4.dim("\u2192");
1746
- console.log(` ${chalk4.bold(symbol.padEnd(8))} ${oldPct}% ${arrow} ${newPct}%`);
1747
- }
1724
+ const newMaxSlippageBps = opts.maxSlippage ? Number(opts.maxSlippage) : void 0;
1725
+ if (newMaxSlippageBps !== void 0 && (!Number.isInteger(newMaxSlippageBps) || newMaxSlippageBps <= 0)) {
1726
+ console.error(chalk4.red(`--max-slippage must be a positive integer bps, got '${opts.maxSlippage}'`));
1727
+ process.exit(1);
1748
1728
  }
1749
1729
  if (opts.dryRun) {
1750
1730
  console.log();
1751
1731
  console.log(chalk4.yellow("Dry run \u2014 no transactions sent."));
1752
1732
  console.log(chalk4.dim("The rebalance would:"));
1753
- console.log(chalk4.dim(" 1. Sell all current token positions back to " + assetSymbol));
1754
- console.log(chalk4.dim(" 2. Re-buy at " + (newWeightsBps ? "new" : "current") + " target weights"));
1733
+ if (newMaxSlippageBps !== void 0) {
1734
+ console.log(chalk4.dim(" 0. Tighten max slippage to " + newMaxSlippageBps + " bps"));
1735
+ }
1736
+ console.log(chalk4.dim(" 1. Price every allocation off its bound push feed"));
1737
+ console.log(chalk4.dim(` 2. Trade each slot's drift back to its target weight, via ${assetSymbol}`));
1755
1738
  console.log();
1756
1739
  return;
1757
1740
  }
1758
- if (newWeightsBps) {
1759
- const maxSlip = Number(opts.maxSlippage || "0");
1760
- const swapData = await publicClient.readContract({
1761
- address: clone,
1762
- abi: PORTFOLIO_STRATEGY_ABI,
1763
- functionName: "getSwapExtraData"
1764
- });
1765
- const updateSpinner = ora3("Updating target weights...").start();
1741
+ if (newMaxSlippageBps !== void 0) {
1742
+ const updateSpinner = ora3("Tightening max slippage...").start();
1766
1743
  try {
1767
1744
  const innerData = encodeAbiParameters3(
1768
1745
  [{ type: "uint256[]" }, { type: "uint256" }, { type: "bytes[]" }],
1769
- [newWeightsBps.map((w) => BigInt(w)), BigInt(maxSlip), swapData]
1746
+ [[], BigInt(newMaxSlippageBps), []]
1770
1747
  );
1771
1748
  const updateHash = await writeContractWithRetry({
1772
1749
  account,
@@ -1778,25 +1755,25 @@ function registerStrategyTemplateCommands(strategy2) {
1778
1755
  });
1779
1756
  const receipt = await waitForReceipt(updateHash);
1780
1757
  if (receipt.status === "reverted") throw new Error("updateParams reverted");
1781
- updateSpinner.succeed("Target weights updated");
1758
+ updateSpinner.succeed(`Max slippage tightened to ${newMaxSlippageBps} bps`);
1782
1759
  console.log(chalk4.dim(` Tx: ${getExplorerUrl(updateHash)}`));
1783
1760
  } catch (err) {
1784
- updateSpinner.fail("Failed to update weights");
1761
+ updateSpinner.fail("Failed to tighten slippage");
1785
1762
  console.error(chalk4.red(formatContractError(err)));
1786
1763
  process.exit(1);
1787
1764
  }
1788
1765
  }
1789
- const rebalanceSpinner = ora3("Rebalancing portfolio (sell all \u2192 re-buy at targets)...").start();
1766
+ const rebalanceSpinner = ora3("Rebalancing portfolio (trading each slot's drift)...").start();
1790
1767
  try {
1791
1768
  const rebalanceHash = await writeContractWithRetry({
1792
1769
  account,
1793
1770
  chain,
1794
1771
  address: clone,
1795
1772
  abi: PORTFOLIO_STRATEGY_ABI,
1796
- functionName: "rebalance"
1773
+ functionName: "rebalanceDelta"
1797
1774
  });
1798
1775
  const receipt = await waitForReceipt(rebalanceHash);
1799
- if (receipt.status === "reverted") throw new Error("rebalance() reverted on-chain");
1776
+ if (receipt.status === "reverted") throw new Error("rebalanceDelta() reverted on-chain");
1800
1777
  rebalanceSpinner.succeed("Portfolio rebalanced");
1801
1778
  console.log(chalk4.dim(` Tx: ${getExplorerUrl(rebalanceHash)}`));
1802
1779
  } catch (err) {
@@ -1945,7 +1922,7 @@ function registerVeniceCommands(program2) {
1945
1922
  console.log(chalk5.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
1946
1923
  console.log(chalk5.dim(" Saved to ~/.sherwood/config.json"));
1947
1924
  try {
1948
- const { createVeniceProvisionAttestation, getEasScanUrl } = await import("./eas-KMDAMLXW.js");
1925
+ const { createVeniceProvisionAttestation, getEasScanUrl } = await import("./eas-VFTWEI4K.js");
1949
1926
  const attestation = await createVeniceProvisionAttestation(account.address);
1950
1927
  if (attestation) {
1951
1928
  console.log(chalk5.dim(` Attested: ${getEasScanUrl(attestation.uid)}`));
@@ -2301,10 +2278,10 @@ ${opts.prompt}`;
2301
2278
  console.log(chalk5.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
2302
2279
  }
2303
2280
  try {
2304
- const { createVeniceInferenceAttestation, getEasScanUrl } = await import("./eas-KMDAMLXW.js");
2281
+ const { createVeniceInferenceAttestation, getEasScanUrl } = await import("./eas-VFTWEI4K.js");
2305
2282
  const { keccak256: keccak2562, toHex, isAddress: isAddr } = await import("viem");
2306
2283
  const { getChainContracts: getChainContracts2 } = await import("./config-ZGFS4I7K.js");
2307
- const { getChain: getActiveChain } = await import("./network-FEHRFDPJ.js");
2284
+ const { getChain: getActiveChain } = await import("./network-7445KSCF.js");
2308
2285
  const vaultRecipient = opts.vault && isAddr(opts.vault) ? opts.vault : getChainContracts2(getActiveChain().id).vault;
2309
2286
  const promptHash = keccak2562(toHex(userContent)).slice(0, 18);
2310
2287
  const attestation = await createVeniceInferenceAttestation(
@@ -2602,7 +2579,7 @@ function registerAllowanceCommands(program2) {
2602
2579
  }
2603
2580
 
2604
2581
  // src/commands/proposal.ts
2605
- import { isAddress as isAddress7, encodeFunctionData as encodeFunctionData3, parseUnits as parseUnits8 } from "viem";
2582
+ import { isAddress as isAddress7, encodeFunctionData as encodeFunctionData3, formatUnits as formatUnits8, parseUnits as parseUnits8 } from "viem";
2606
2583
  import chalk8 from "chalk";
2607
2584
  import ora6 from "ora";
2608
2585
  import { readFileSync as readFileSync2 } from "fs";
@@ -3300,8 +3277,8 @@ function printSimulationResult(result, callType) {
3300
3277
  }
3301
3278
  async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
3302
3279
  try {
3303
- const xmtp = await import("./xmtp-KW73BGVO.js");
3304
- const { getAccount: getAccount2 } = await import("./client-3SE632Q2.js");
3280
+ const xmtp = await import("./xmtp-7LAWDKJT.js");
3281
+ const { getAccount: getAccount2 } = await import("./client-C6N2ASTH.js");
3305
3282
  const group = await xmtp.getGroup("", subdomain);
3306
3283
  const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
3307
3284
  const criticals = allRisks.filter((r) => r.level === "critical");
@@ -3410,47 +3387,12 @@ function parseCallsFile(path) {
3410
3387
  value: BigInt(c.value || "0")
3411
3388
  }));
3412
3389
  }
3413
- function parseSandboxCallsFile(path) {
3414
- const raw = readFileSync2(path, "utf-8");
3415
- const parsed = JSON.parse(raw);
3416
- if (!Array.isArray(parsed)) {
3417
- console.error(chalk8.red(" sandbox calls file must be a JSON array of {target, data} objects"));
3418
- process.exit(1);
3390
+ function parseWoodAmount(raw, flag) {
3391
+ const s = String(raw ?? "").trim();
3392
+ if (!/^\d+(\.\d+)?$/.test(s)) {
3393
+ throw new Error(`${flag} must be a non-negative decimal WOOD amount, got "${s}".`);
3419
3394
  }
3420
- return parsed.map((c, i) => {
3421
- if (!c || typeof c !== "object") {
3422
- console.error(chalk8.red(` sandbox.calls[${i}] must be an object`));
3423
- process.exit(1);
3424
- }
3425
- const rec = c;
3426
- if (rec.value !== void 0 && rec.value !== null) {
3427
- console.error(
3428
- chalk8.red(
3429
- ` sandbox.calls[${i}] must be (address,bytes) only \u2014 ICallSandbox.Call has no value field.`
3430
- )
3431
- );
3432
- process.exit(1);
3433
- }
3434
- if (typeof rec.target !== "string" || !isAddress7(rec.target)) {
3435
- console.error(chalk8.red(` sandbox.calls[${i}].target must be a 0x-prefixed address`));
3436
- process.exit(1);
3437
- }
3438
- if (typeof rec.data !== "string" || !/^0x[0-9a-fA-F]*$/.test(rec.data)) {
3439
- console.error(chalk8.red(` sandbox.calls[${i}].data must be a 0x-prefixed hex string`));
3440
- process.exit(1);
3441
- }
3442
- return { target: rec.target, data: rec.data };
3443
- });
3444
- }
3445
- function parseSandboxTokens(list) {
3446
- if (list === void 0 || list.trim().length === 0) return [];
3447
- return list.split(",").map((x) => x.trim()).filter((x) => x.length > 0).map((a, i) => {
3448
- if (!isAddress7(a)) {
3449
- console.error(chalk8.red(` --sandbox-tokens[${i}] is not a 0x-prefixed address: ${a}`));
3450
- process.exit(1);
3451
- }
3452
- return a;
3453
- });
3395
+ return parseUnits8(s, 18);
3454
3396
  }
3455
3397
  var GUARDIAN_REGISTRY_ABI = [
3456
3398
  {
@@ -3488,7 +3430,10 @@ var GUARDIAN_REGISTRY_ABI = [
3488
3430
  inputs: [
3489
3431
  { name: "governor", type: "address" },
3490
3432
  { name: "proposalId", type: "uint256" },
3491
- { name: "support", type: "uint8" }
3433
+ { name: "support", type: "uint8" },
3434
+ // The approver's declaration: WOOD it puts behind this proposal,
3435
+ // clamped to its free budget by ExposureLedger. Ignored on a Block.
3436
+ { name: "lockWood", type: "uint256" }
3492
3437
  ],
3493
3438
  outputs: [],
3494
3439
  stateMutability: "nonpayable"
@@ -3746,171 +3691,6 @@ function registerProposalCommands(program2) {
3746
3691
  process.exit(1);
3747
3692
  }
3748
3693
  });
3749
- proposal.command("create-sandbox").description("Submit a strategy proposal with a CallSandbox payload (ICallSandbox.Call is (address,bytes) only \u2014 no value)").requiredOption("--vault <address>", "Vault address the proposal targets").requiredOption("--name <name>", "Strategy name").requiredOption("--description <text>", "Strategy rationale and risk summary").requiredOption("--duration <duration>", "Strategy duration (e.g. 7d, 24h, 3600)").requiredOption("--execute-calls <path>", "Path to JSON file with execute Call[] array").requiredOption("--settle-calls <path>", "Path to JSON file with settlement Call[] array").requiredOption(
3750
- "--sandbox-calls <path>",
3751
- "Path to JSON file of ICallSandbox.Call[] \u2014 [{target, data}, ...]. A value field is refused."
3752
- ).requiredOption(
3753
- "--sandbox-funding <amount>",
3754
- "Vault-asset amount the sandbox is funded with (decimals resolved from the asset). Must be > 0 and <= --max-capital."
3755
- ).option("--sandbox-tokens <list>", "Comma-separated declared non-asset token addresses the payload may hold").option("--strategy <address>", "Live-NAV strategy clone address (default: none \u2014 queue-only)").option(
3756
- "--max-capital <amount>",
3757
- "REQUIRED. Ceiling on what the execute batch may deploy, in vault-asset units."
3758
- ).option(
3759
- "--max-drawdown-bps <bps>",
3760
- "Declared loss allowance in bps of --max-capital (0-10000, default 2000 = 20%)."
3761
- ).option("--execute-caps <list>", "Comma-separated per-execute-call outflow caps in asset units").option("--settle-caps <list>", "Comma-separated per-settlement-call outflow caps in asset units").option("--metadata-uri <uri>", "Override \u2014 skip IPFS upload and use this URI directly").action(async (opts) => {
3762
- try {
3763
- const vault = opts.vault;
3764
- if (!isAddress7(vault)) {
3765
- console.error(chalk8.red(`Invalid vault address: ${opts.vault}`));
3766
- process.exit(1);
3767
- }
3768
- const strategyDuration = parseDuration(opts.duration);
3769
- const executeCalls = parseCallsFile(opts.executeCalls);
3770
- const settleCalls = parseCallsFile(opts.settleCalls);
3771
- const sandboxCalls = parseSandboxCallsFile(opts.sandboxCalls);
3772
- const declaredTokens = parseSandboxTokens(opts.sandboxTokens);
3773
- const ZERO_STRATEGY = "0x0000000000000000000000000000000000000000";
3774
- let strategy2 = ZERO_STRATEGY;
3775
- if (opts.strategy) {
3776
- if (!isAddress7(opts.strategy)) {
3777
- console.error(chalk8.red(`Invalid strategy address: ${opts.strategy}`));
3778
- process.exit(1);
3779
- }
3780
- strategy2 = opts.strategy;
3781
- }
3782
- const envelope = await resolveRiskEnvelope(opts, vault);
3783
- const asset = await getAssetAddress();
3784
- const decimals = await getPublicClient().readContract({
3785
- address: asset,
3786
- abi: ERC20_ABI,
3787
- functionName: "decimals"
3788
- });
3789
- const funding = parseUnits8(String(opts.sandboxFunding), decimals);
3790
- const executeCallCaps = resolveCaps(
3791
- opts.executeCaps,
3792
- executeCalls.length,
3793
- envelope.maxCapital,
3794
- "--execute-caps"
3795
- );
3796
- const settleCallCaps = resolveCaps(
3797
- opts.settleCaps,
3798
- settleCalls.length,
3799
- 0n,
3800
- "--settle-caps"
3801
- );
3802
- const buildAction = async (metadataURI2) => encodeProposeWithSandbox(
3803
- {
3804
- vault,
3805
- governor: await getGovernorOf(vault),
3806
- strategy: strategy2,
3807
- metadataURI: metadataURI2,
3808
- strategyDuration,
3809
- envelope,
3810
- executeCalls,
3811
- executeCallCaps,
3812
- settlementCalls: settleCalls,
3813
- settlementCallCaps: settleCallCaps,
3814
- sandbox: { funding, calls: sandboxCalls, declaredTokens }
3815
- },
3816
- getChain().id
3817
- );
3818
- if (isCalldataOnly()) {
3819
- if (!opts.metadataUri) {
3820
- console.error(
3821
- chalk8.red(
3822
- "--calldata-only requires --metadata-uri (IPFS metadata upload needs a signing wallet)"
3823
- )
3824
- );
3825
- process.exit(1);
3826
- }
3827
- try {
3828
- emitCalldata(await buildAction(opts.metadataUri));
3829
- } catch (err) {
3830
- console.error(chalk8.red(err instanceof Error ? err.message : String(err)));
3831
- process.exit(1);
3832
- }
3833
- return;
3834
- }
3835
- let metadataURI = opts.metadataUri || "";
3836
- if (!metadataURI) {
3837
- const spinner2 = ora6({ text: W3("Uploading metadata to IPFS..."), color: "green" }).start();
3838
- try {
3839
- const account = getAccount();
3840
- const metadata = {
3841
- schema: "sherwood/proposal/v1",
3842
- name: opts.name,
3843
- description: opts.description,
3844
- chain: getNetwork(),
3845
- strategies: [],
3846
- terms: {},
3847
- links: {}
3848
- };
3849
- const proposalMeta = {
3850
- ...metadata,
3851
- proposer: account.address,
3852
- vault,
3853
- strategyDuration: Number(strategyDuration),
3854
- sandbox: true,
3855
- createdAt: Math.floor(Date.now() / 1e3)
3856
- };
3857
- metadataURI = await uploadMetadata(proposalMeta);
3858
- spinner2.succeed(G3(`Metadata pinned: ${DIM3(metadataURI)}`));
3859
- } catch (err) {
3860
- spinner2.warn(chalk8.yellow("IPFS upload failed \u2014 using inline metadata"));
3861
- const json = JSON.stringify({ name: opts.name, description: opts.description, vault, sandbox: true });
3862
- metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
3863
- }
3864
- }
3865
- console.log();
3866
- console.log(LABEL3(" \u25C6 Sandbox Proposal Summary"));
3867
- SEP3();
3868
- console.log(W3(` Name: ${BOLD3(opts.name)}`));
3869
- console.log(W3(` Vault: ${G3(vault)}`));
3870
- console.log(W3(` Duration: ${formatDurationShort(strategyDuration)}`));
3871
- console.log(W3(` Calls: ${executeCalls.length} execute + ${settleCalls.length} settle + ${sandboxCalls.length} sandbox`));
3872
- console.log(W3(` Sandbox funding: ${opts.sandboxFunding}`));
3873
- console.log(W3(` Metadata: ${DIM3(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
3874
- SEP3();
3875
- const spinner = ora6({ text: W3("Submitting sandbox proposal..."), color: "green" }).start();
3876
- let action;
3877
- try {
3878
- action = await buildAction(metadataURI);
3879
- } catch (err) {
3880
- spinner.fail(err instanceof Error ? err.message : String(err));
3881
- process.exit(1);
3882
- }
3883
- const tx = action.txs[0];
3884
- const hash = await sendTxWithRetry({
3885
- account: getAccount(),
3886
- chain: getChain(),
3887
- to: tx.to,
3888
- data: tx.data,
3889
- value: 0n
3890
- });
3891
- const receipt = await waitForReceipt(hash);
3892
- let proposalId = parseProposalIdFromLogs(receipt.logs);
3893
- if (proposalId === void 0) {
3894
- try {
3895
- proposalId = await proposalCount(vault);
3896
- } catch {
3897
- proposalId = 0n;
3898
- }
3899
- }
3900
- spinner.succeed(G3("Sandbox proposal submitted"));
3901
- console.log();
3902
- console.log(LABEL3(" \u25C6 Sandbox Proposal Created"));
3903
- SEP3();
3904
- console.log(W3(` Proposal ID: ${G3(`#${proposalId}`)}`));
3905
- console.log(W3(` Tx: ${DIM3(getExplorerUrl(receipt.transactionHash))}`));
3906
- SEP3();
3907
- console.log();
3908
- } catch (err) {
3909
- console.error(chalk8.red(`
3910
- \u2716 ${formatContractError(err)}`));
3911
- process.exit(1);
3912
- }
3913
- });
3914
3694
  proposal.command("list").description("List a vault's proposals (per-vault governor \u2014 IDs are scoped to the vault)").requiredOption("--vault <address>", "Vault whose proposals to list").option("--state <filter>", "Filter by state: draft, pending, approved, executed, settled, all", "all").action(async (opts) => {
3915
3695
  const spinner = ora6("Loading proposals...").start();
3916
3696
  try {
@@ -3943,7 +3723,7 @@ function registerProposalCommands(program2) {
3943
3723
  console.log(BOLD3(`Proposals (${proposals.length})`));
3944
3724
  console.log(DIM3("\u2500".repeat(90)));
3945
3725
  console.log(
3946
- DIM3(" ID ") + DIM3("Agent".padEnd(14)) + DIM3("State".padEnd(12)) + DIM3("Fee".padEnd(8)) + DIM3("Votes (For/Against)".padEnd(22)) + DIM3("Duration".padEnd(10)) + DIM3("Created")
3726
+ DIM3(" ID ") + DIM3("Agent".padEnd(14)) + DIM3("State".padEnd(12)) + DIM3("Fee".padEnd(8)) + DIM3("Against/Votable".padEnd(22)) + DIM3("Duration".padEnd(10)) + DIM3("Created")
3947
3727
  );
3948
3728
  console.log(DIM3("\u2500".repeat(90)));
3949
3729
  for (const p of proposals) {
@@ -3951,7 +3731,7 @@ function registerProposalCommands(program2) {
3951
3731
  const created = p.snapshotTimestamp > 0n ? new Date(Number(p.snapshotTimestamp) * 1e3).toLocaleDateString() : "\u2014";
3952
3732
  const agent = `${p.proposer.slice(0, 6)}...${p.proposer.slice(-4)}`;
3953
3733
  const dur = formatDurationShort(p.strategyDuration);
3954
- const votes = `${formatShares(p.votesFor)}/${formatShares(p.votesAgainst)}`;
3734
+ const votes = `${formatShares(p.votesAgainst)}/${formatShares(p.votableSupply)}`;
3955
3735
  const fee = `${Number(p.performanceFeeBps) / 100}%`;
3956
3736
  console.log(
3957
3737
  ` ${String(p.id).padEnd(4)}${agent.padEnd(14)}${state.padEnd(12)}${fee.padEnd(8)}${votes.padEnd(22)}${dur.padEnd(10)}${created}`
@@ -3977,11 +3757,9 @@ function registerProposalCommands(program2) {
3977
3757
  }
3978
3758
  const p = await getProposal(vault, id);
3979
3759
  const state = await getProposalState(vault, id);
3980
- const params = await getGovernorParams(vault);
3981
3760
  spinner.stop();
3982
3761
  const stateLabel = PROPOSAL_STATES[state] || "Unknown";
3983
- const totalVotes = p.votesFor + p.votesAgainst;
3984
- const quorumNeeded = totalVotes > 0n ? `${Number(params.vetoThresholdBps) / 100}%` : "\u2014";
3762
+ const vetoBar = p.votableSupply > 0n ? p.votableSupply * p.vetoThresholdBps / 10000n || 1n : null;
3985
3763
  console.log();
3986
3764
  console.log(LABEL3(` \u25C6 Proposal #${p.id}`));
3987
3765
  SEP3();
@@ -4009,10 +3787,11 @@ function registerProposalCommands(program2) {
4009
3787
  console.log(W3(` Executed At: ${formatTimestamp(p.executedAt)}`));
4010
3788
  console.log();
4011
3789
  console.log(LABEL3(" Votes"));
4012
- console.log(W3(` For: ${formatShares(p.votesFor)}`));
4013
3790
  console.log(W3(` Against: ${formatShares(p.votesAgainst)}`));
4014
- console.log(W3(` Abstain: ${formatShares(p.votesAbstain)}`));
4015
- console.log(W3(` Veto Threshold: ${quorumNeeded}`));
3791
+ console.log(W3(` Votable Supply: ${formatShares(p.votableSupply)}`));
3792
+ console.log(W3(
3793
+ ` Veto Threshold: ${vetoBar === null ? DIM3("\u2014 (no votable supply \u2014 veto check skipped)") : `${Number(p.vetoThresholdBps) / 100}% (${formatShares(vetoBar)})`}`
3794
+ ));
4016
3795
  if (state === PROPOSAL_STATE.Executed || state === PROPOSAL_STATE.Settled) {
4017
3796
  try {
4018
3797
  const cap = await getCapitalSnapshot(vault, id);
@@ -4099,15 +3878,19 @@ function registerProposalCommands(program2) {
4099
3878
  process.exit(1);
4100
3879
  }
4101
3880
  });
4102
- proposal.command("review-vote").description("Cast a guardian review vote (Approve or Block) on a live review").requiredOption("--id <proposalId>", "Proposal ID").requiredOption("--vault <address>", "Vault the proposal belongs to (per-vault governor)").requiredOption("--support <approve|block>", "Guardian review vote: approve or block").action(async (opts) => {
3881
+ proposal.command("review-vote").description("Cast a guardian review vote (Approve or Block) on a live review").requiredOption("--id <proposalId>", "Proposal ID").requiredOption("--vault <address>", "Vault the proposal belongs to (per-vault governor)").requiredOption("--support <approve|block>", "Guardian review vote: approve or block").requiredOption(
3882
+ "--lock-wood <wood>",
3883
+ "WOOD you declare behind an Approve (decimal WOOD). Clamped to your free budget by ExposureLedger; ignored on a Block."
3884
+ ).action(async (opts) => {
4103
3885
  try {
4104
3886
  const proposalId = parseBigIntArg(opts.id, "proposal ID");
4105
3887
  const vault = parseVaultOption(opts.vault);
4106
3888
  const vote2 = parseGuardianReviewVote(String(opts.support));
3889
+ const lockWood = parseWoodAmount(opts.lockWood, "--lock-wood");
4107
3890
  const chainId = getChain().id;
4108
3891
  const governor = await getGovernorOf(vault);
4109
3892
  if (isCalldataOnly()) {
4110
- emitCalldata(encodeVoteOnProposal({ governor, proposalId, vote: vote2 }, chainId));
3893
+ emitCalldata(encodeVoteOnProposal({ governor, proposalId, vote: vote2, lockWood }, chainId));
4111
3894
  return;
4112
3895
  }
4113
3896
  const account = getAccount();
@@ -4168,6 +3951,9 @@ function registerProposalCommands(program2) {
4168
3951
  SEP3();
4169
3952
  if (vote2 === "Approve") {
4170
3953
  console.log(chalk8.yellow.bold(" \u26A0 UNDERWRITING"));
3954
+ console.log(chalk8.yellow(
3955
+ ` Declared lock: ${formatUnits8(lockWood, 18)} WOOD`
3956
+ ));
4171
3957
  console.log(chalk8.yellow(
4172
3958
  " Approve books this proposal's coverage against YOUR own slashable"
4173
3959
  ));
@@ -4185,7 +3971,7 @@ function registerProposalCommands(program2) {
4185
3971
  ));
4186
3972
  SEP3();
4187
3973
  }
4188
- const action = encodeVoteOnProposal({ governor, proposalId, vote: vote2 }, chainId);
3974
+ const action = encodeVoteOnProposal({ governor, proposalId, vote: vote2, lockWood }, chainId);
4189
3975
  const tx = action.txs[0];
4190
3976
  const voteSpinner = ora6({ text: W3("Submitting review vote..."), color: "green" }).start();
4191
3977
  const hash = await sendTxWithRetry({
@@ -4851,7 +4637,7 @@ function registerProposalCommands(program2) {
4851
4637
  }
4852
4638
 
4853
4639
  // src/commands/queue.ts
4854
- import { parseUnits as parseUnits9, formatUnits as formatUnits8, isAddress as isAddress8, parseEventLogs } from "viem";
4640
+ import { parseUnits as parseUnits9, formatUnits as formatUnits9, isAddress as isAddress8, parseEventLogs } from "viem";
4855
4641
  import chalk9 from "chalk";
4856
4642
  import ora7 from "ora";
4857
4643
  var WETH_ABI = [
@@ -5040,7 +4826,7 @@ function registerQueueCommands(program2) {
5040
4826
  );
5041
4827
  if (ethBalance < shortfall + minGas) {
5042
4828
  throw new Error(
5043
- `Insufficient ETH on ${getChain().name}. Have ${formatUnits8(ethBalance, 18)} ETH, need ${formatUnits8(shortfall, 18)} to wrap + ~${formatUnits8(minGas, 18)} for gas.`
4829
+ `Insufficient ETH on ${getChain().name}. Have ${formatUnits9(ethBalance, 18)} ETH, need ${formatUnits9(shortfall, 18)} to wrap + ~${formatUnits9(minGas, 18)} for gas.`
5044
4830
  );
5045
4831
  }
5046
4832
  spinner.text = "Wrapping ETH \u2192 WETH...";
@@ -8051,9 +7837,9 @@ try {
8051
7837
  } catch {
8052
7838
  }
8053
7839
  var require2 = createRequire(import.meta.url);
8054
- var CLI_VERSION = "0.86.1";
7840
+ var CLI_VERSION = "0.87.0";
8055
7841
  async function loadXmtp() {
8056
- return import("./xmtp-KW73BGVO.js");
7842
+ return import("./xmtp-7LAWDKJT.js");
8057
7843
  }
8058
7844
  async function loadCron() {
8059
7845
  return import("./cron-E3UAZF5B.js");
@@ -8099,7 +7885,7 @@ program.name("sherwood").description("CLI for agent-managed onchain vaults").ver
8099
7885
  }).addOption(
8100
7886
  new Option(
8101
7887
  "--chain <network>",
8102
- "Target network (default: robinhood-fork, chain 9994663 \u2014 where the product lives; robinhood-testnet is chain 46630)"
7888
+ "Target network (default: robinhood-fork, chain 9994663 \u2014 where the product lives; robinhood-testnet is chain 46630 and still runs a PRE-V1 stack this CLI cannot talk to)"
8103
7889
  ).choices(VALID_NETWORKS).default(DEFAULT_NETWORK)
8104
7890
  ).option(
8105
7891
  "--calldata-only",
@@ -8724,7 +8510,7 @@ vaultCmd.command("add").description("Register an agent on a vault (creator only)
8724
8510
  agentId = BigInt(opts.agentId);
8725
8511
  } else {
8726
8512
  spinner.text = "Looking up ERC-8004 identity from wallet...";
8727
- const { lookupAgentIdByWallet } = await import("./identity-ATWV2O7Y.js");
8513
+ const { lookupAgentIdByWallet } = await import("./identity-OLD25QEP.js");
8728
8514
  const resolved = await lookupAgentIdByWallet(agentWallet);
8729
8515
  if (resolved === null) {
8730
8516
  spinner.fail("Agent wallet does not own an ERC-8004 identity NFT");
@@ -9408,7 +9194,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
9408
9194
  `));
9409
9195
  process.exit(1);
9410
9196
  }
9411
- const sharesDisplay = formatUnits9(shares, shareDecimals);
9197
+ const sharesDisplay = formatUnits10(shares, shareDecimals);
9412
9198
  const spinner = ora9(`Redeeming ${sharesDisplay} shares...`).start();
9413
9199
  try {
9414
9200
  const { hash, assetsOut } = await redeem(
@@ -9417,7 +9203,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
9417
9203
  );
9418
9204
  spinner.succeed(`Redeemed: ${hash}`);
9419
9205
  console.log(chalk17.dim(` ${getExplorerUrl(hash)}`));
9420
- console.log(` Assets received: ${formatUnits9(assetsOut, assetDecimals)}`);
9206
+ console.log(` Assets received: ${formatUnits10(assetsOut, assetDecimals)}`);
9421
9207
  } catch (err) {
9422
9208
  spinner.fail("Redeem failed");
9423
9209
  console.error(chalk17.red(formatContractError(err)));
@@ -9427,7 +9213,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
9427
9213
  var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
9428
9214
  registerStrategyTemplateCommands(strategy);
9429
9215
  program.command("providers").description("List available providers (research + swap routing)").action(async () => {
9430
- const { listProviders } = await import("./providers-BMOHHVUN.js");
9216
+ const { listProviders } = await import("./providers-KZNCCUKT.js");
9431
9217
  for (const info of listProviders()) {
9432
9218
  console.log(`
9433
9219
  ${info.name} (${info.type})`);
@@ -9437,7 +9223,7 @@ ${info.name} (${info.type})`);
9437
9223
  }
9438
9224
  });
9439
9225
  try {
9440
- const { registerChatCommands } = await import("./chat-ETZSKQDI.js");
9226
+ const { registerChatCommands } = await import("./chat-OZAAN5LT.js");
9441
9227
  registerChatCommands(program);
9442
9228
  } catch {
9443
9229
  program.command("chat <name> [action] [actionArgs...]").description("Vault chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
@@ -9447,7 +9233,7 @@ try {
9447
9233
  process.exit(1);
9448
9234
  });
9449
9235
  }
9450
- var { registerSessionCommands } = await import("./session-HVRZ6AJM.js");
9236
+ var { registerSessionCommands } = await import("./session-A7CYZSSA.js");
9451
9237
  registerSessionCommands(program);
9452
9238
  registerVeniceCommands(program);
9453
9239
  registerAllowanceCommands(program);
@@ -9456,11 +9242,11 @@ registerProposalCommands(program);
9456
9242
  registerQueueCommands(program);
9457
9243
  registerGovernorCommands(program);
9458
9244
  registerGuardianCommands(program);
9459
- var { registerResearchCommands } = await import("./research-W74PNYPO.js");
9245
+ var { registerResearchCommands } = await import("./research-ARFBFXIT.js");
9460
9246
  registerResearchCommands(program);
9461
- var { registerAgentCommands } = await import("./agent-TBLC3WNJ.js");
9247
+ var { registerAgentCommands } = await import("./agent-A2JEYGQS.js");
9462
9248
  registerAgentCommands(program);
9463
- var { registerTradeCommands } = await import("./trade-EOQY72L7.js");
9249
+ var { registerTradeCommands } = await import("./trade-ZCK332E4.js");
9464
9250
  registerTradeCommands(program);
9465
9251
  registerGridCommand(program);
9466
9252
  var configCmd = program.command("config");