@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.
- package/dist/{chat-JYAJMP4D.js → chat-3SAX4VRO.js} +7 -7
- package/dist/{chunk-LVPBJ7MI.js → chunk-35536GNW.js} +2 -2
- package/dist/{chunk-4Y6Y4SVH.js → chunk-5NN424VN.js} +4 -4
- package/dist/{chunk-B42ZCCZ7.js → chunk-5S2TBADL.js} +4 -2
- package/dist/chunk-5S2TBADL.js.map +1 -0
- package/dist/{chunk-VO6DCRWV.js → chunk-LMDHM36X.js} +4 -4
- package/dist/{chunk-QGZUMIVO.js → chunk-NGET2RWT.js} +16 -7
- package/dist/chunk-NGET2RWT.js.map +1 -0
- package/dist/{chunk-Y7LS6DEF.js → chunk-PEJPTKLK.js} +5 -5
- package/dist/{chunk-JR5K5WVR.js → chunk-R75DM3VL.js} +163 -10
- package/dist/chunk-R75DM3VL.js.map +1 -0
- package/dist/{chunk-ASJTFFZH.js → chunk-R7Q2L6VV.js} +3 -3
- package/dist/{chunk-G7JQRLQE.js → chunk-ZIH3SCFJ.js} +5 -5
- package/dist/{client-SCIY6SUP.js → client-XG6LL6TS.js} +4 -4
- package/dist/{config-BGS5MX4D.js → config-EHCEKT2B.js} +2 -2
- package/dist/{eas-X5UIEM6D.js → eas-ZMTIOZH6.js} +6 -6
- package/dist/{governor-ZKRSAHG4.js → governor-JIXAG6WU.js} +6 -6
- package/dist/index.js +609 -74
- package/dist/index.js.map +1 -1
- package/dist/{network-UTSOP7EF.js → network-UVMYTKQX.js} +3 -3
- package/dist/price-AGCWXLZ6.js +156 -0
- package/dist/price-AGCWXLZ6.js.map +1 -0
- package/dist/research-2I6AA3BI.js +14 -0
- package/dist/{research-ZW6XVTGZ.js → research-KUIZM6AK.js} +9 -9
- package/dist/{session-XZNKLK3I.js → session-2FIR4LJP.js} +12 -12
- package/dist/{trade-OJM5HNHL.js → trade-UTM3DSO3.js} +16 -16
- package/dist/{xmtp-XKHXATPQ.js → xmtp-B2XFVPIV.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-B42ZCCZ7.js.map +0 -1
- package/dist/chunk-JR5K5WVR.js.map +0 -1
- package/dist/chunk-QGZUMIVO.js.map +0 -1
- package/dist/research-SJ6D3L2B.js +0 -14
- /package/dist/{chat-JYAJMP4D.js.map → chat-3SAX4VRO.js.map} +0 -0
- /package/dist/{chunk-LVPBJ7MI.js.map → chunk-35536GNW.js.map} +0 -0
- /package/dist/{chunk-4Y6Y4SVH.js.map → chunk-5NN424VN.js.map} +0 -0
- /package/dist/{chunk-VO6DCRWV.js.map → chunk-LMDHM36X.js.map} +0 -0
- /package/dist/{chunk-Y7LS6DEF.js.map → chunk-PEJPTKLK.js.map} +0 -0
- /package/dist/{chunk-ASJTFFZH.js.map → chunk-R7Q2L6VV.js.map} +0 -0
- /package/dist/{chunk-G7JQRLQE.js.map → chunk-ZIH3SCFJ.js.map} +0 -0
- /package/dist/{client-SCIY6SUP.js.map → client-XG6LL6TS.js.map} +0 -0
- /package/dist/{config-BGS5MX4D.js.map → config-EHCEKT2B.js.map} +0 -0
- /package/dist/{eas-X5UIEM6D.js.map → eas-ZMTIOZH6.js.map} +0 -0
- /package/dist/{governor-ZKRSAHG4.js.map → governor-JIXAG6WU.js.map} +0 -0
- /package/dist/{network-UTSOP7EF.js.map → network-UVMYTKQX.js.map} +0 -0
- /package/dist/{research-SJ6D3L2B.js.map → research-2I6AA3BI.js.map} +0 -0
- /package/dist/{research-ZW6XVTGZ.js.map → research-KUIZM6AK.js.map} +0 -0
- /package/dist/{session-XZNKLK3I.js.map → session-2FIR4LJP.js.map} +0 -0
- /package/dist/{trade-OJM5HNHL.js.map → trade-UTM3DSO3.js.map} +0 -0
- /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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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(
|
|
803
|
-
|
|
804
|
-
|
|
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-
|
|
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-
|
|
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
|
|
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: ${
|
|
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-
|
|
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: ${
|
|
1362
|
-
console.log(` VVV (unstaked): ${
|
|
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}: ${
|
|
1899
|
+
console.log(` ${label}: ${formatUnits3(balance, 18)} sVVV`);
|
|
1368
1900
|
}
|
|
1369
1901
|
console.log(chalk2.bold("\n Your Wallet"));
|
|
1370
|
-
console.log(` sVVV: ${
|
|
1371
|
-
console.log(` Pending rewards: ${
|
|
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-
|
|
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-
|
|
1443
|
-
const { getChain: getActiveChain } = await import("./network-
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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: ${
|
|
1597
|
-
console.log(` Deposited: ${
|
|
1598
|
-
console.log(` Profit: ${
|
|
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 (${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
1719
|
-
console.log(` Deposited: ${
|
|
1720
|
-
console.log(` Profit: ${
|
|
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}: ${
|
|
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
|
|
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 =
|
|
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-
|
|
2573
|
-
const { getAccount: getAccount2 } = await import("./client-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
4788
|
+
var { registerResearchCommands } = await import("./research-KUIZM6AK.js");
|
|
4254
4789
|
registerResearchCommands(program);
|
|
4255
|
-
var { registerTradeCommands } = await import("./trade-
|
|
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) => {
|