@sherwoodagent/cli 0.15.3 → 0.17.1
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-A2ORZVU3.js → chat-G5TRNY5S.js} +4 -4
- package/dist/chunk-A4F6KTXA.js +442 -0
- package/dist/chunk-A4F6KTXA.js.map +1 -0
- package/dist/{chunk-LACUMLU4.js → chunk-EMPYAZNP.js} +2 -2
- package/dist/{chunk-GC5J54OC.js → chunk-UQKNCRDW.js} +120 -72
- package/dist/chunk-UQKNCRDW.js.map +1 -0
- package/dist/{chunk-AK7BD7KH.js → chunk-X3L57WGW.js} +2 -2
- package/dist/{eas-V6B6XGBK.js → eas-INBAMX7K.js} +3 -3
- package/dist/governor-P6YV4YR7.js +77 -0
- package/dist/governor-P6YV4YR7.js.map +1 -0
- package/dist/index.js +892 -837
- package/dist/index.js.map +1 -1
- package/dist/{research-63D7YID3.js → research-FNH3VT57.js} +3 -3
- package/dist/{session-3YRZI426.js → session-VEF5BZIX.js} +4 -4
- package/dist/{xmtp-BSTLCZWG.js → xmtp-DX73F6I4.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-GC5J54OC.js.map +0 -1
- /package/dist/{chat-A2ORZVU3.js.map → chat-G5TRNY5S.js.map} +0 -0
- /package/dist/{chunk-LACUMLU4.js.map → chunk-EMPYAZNP.js.map} +0 -0
- /package/dist/{chunk-AK7BD7KH.js.map → chunk-X3L57WGW.js.map} +0 -0
- /package/dist/{eas-V6B6XGBK.js.map → eas-INBAMX7K.js.map} +0 -0
- /package/dist/{research-63D7YID3.js.map → research-FNH3VT57.js.map} +0 -0
- /package/dist/{session-3YRZI426.js.map → session-VEF5BZIX.js.map} +0 -0
- /package/dist/{xmtp-BSTLCZWG.js.map → xmtp-DX73F6I4.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PROPOSAL_STATE,
|
|
4
|
+
PROPOSAL_STATES,
|
|
5
|
+
VOTE_TYPE,
|
|
6
|
+
cancelProposal,
|
|
7
|
+
emergencyCancel,
|
|
8
|
+
emergencySettle,
|
|
9
|
+
executeProposal,
|
|
10
|
+
getCapitalSnapshot,
|
|
11
|
+
getExecuteCalls,
|
|
12
|
+
getGovernorAddress,
|
|
13
|
+
getGovernorParams,
|
|
14
|
+
getProposal,
|
|
15
|
+
getProposalState,
|
|
16
|
+
getRegisteredVaults,
|
|
17
|
+
getSettlementCalls,
|
|
18
|
+
getVoteWeight,
|
|
19
|
+
hasVoted,
|
|
20
|
+
parseDuration,
|
|
21
|
+
proposalCount,
|
|
22
|
+
propose,
|
|
23
|
+
setCooldownPeriod,
|
|
24
|
+
setExecutionWindow,
|
|
25
|
+
setMaxPerformanceFeeBps,
|
|
26
|
+
setMaxStrategyDuration,
|
|
27
|
+
setProtocolFeeBps,
|
|
28
|
+
setVetoThresholdBps,
|
|
29
|
+
setVotingPeriod,
|
|
30
|
+
settleProposal,
|
|
31
|
+
vote
|
|
32
|
+
} from "./chunk-A4F6KTXA.js";
|
|
2
33
|
import {
|
|
3
34
|
fetchMetadata,
|
|
4
35
|
uploadMetadata
|
|
@@ -10,7 +41,7 @@ import {
|
|
|
10
41
|
queryApprovals,
|
|
11
42
|
queryJoinRequests,
|
|
12
43
|
revokeAttestation
|
|
13
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-X3L57WGW.js";
|
|
14
45
|
import {
|
|
15
46
|
approveDepositor,
|
|
16
47
|
deposit,
|
|
@@ -26,23 +57,24 @@ import {
|
|
|
26
57
|
resolveVaultSyndicate,
|
|
27
58
|
setTextRecord,
|
|
28
59
|
setVaultAddress
|
|
29
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-EMPYAZNP.js";
|
|
30
61
|
import {
|
|
62
|
+
AERODROME,
|
|
31
63
|
AGENT_REGISTRY,
|
|
64
|
+
BASE_STRATEGY_ABI,
|
|
32
65
|
EAS_SCHEMAS,
|
|
33
66
|
ERC20_ABI,
|
|
34
67
|
MOONWELL,
|
|
35
68
|
SHERWOOD,
|
|
36
|
-
|
|
69
|
+
STRATEGY_TEMPLATES,
|
|
37
70
|
SYNDICATE_FACTORY_ABI,
|
|
38
|
-
SYNDICATE_GOVERNOR_ABI,
|
|
39
71
|
SYNDICATE_VAULT_ABI,
|
|
40
72
|
TOKENS,
|
|
41
73
|
UNISWAP,
|
|
42
74
|
UNISWAP_QUOTER_V2_ABI,
|
|
43
75
|
VENICE,
|
|
44
76
|
VENICE_STAKING_ABI
|
|
45
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-UQKNCRDW.js";
|
|
46
78
|
import {
|
|
47
79
|
getAccount,
|
|
48
80
|
getPublicClient,
|
|
@@ -76,7 +108,7 @@ import {
|
|
|
76
108
|
import { config as loadDotenv } from "dotenv";
|
|
77
109
|
import { createRequire } from "module";
|
|
78
110
|
import { Command, Option } from "commander";
|
|
79
|
-
import { parseUnits as
|
|
111
|
+
import { parseUnits as parseUnits7, isAddress as isAddress5 } from "viem";
|
|
80
112
|
import chalk7 from "chalk";
|
|
81
113
|
import ora7 from "ora";
|
|
82
114
|
import { input, confirm, select } from "@inquirer/prompts";
|
|
@@ -137,342 +169,622 @@ var UniswapProvider = class {
|
|
|
137
169
|
}
|
|
138
170
|
};
|
|
139
171
|
|
|
140
|
-
// src/commands/strategy-
|
|
141
|
-
import { parseUnits
|
|
172
|
+
// src/commands/strategy-template.ts
|
|
173
|
+
import { parseUnits, isAddress, erc20Abi } from "viem";
|
|
142
174
|
import chalk from "chalk";
|
|
143
175
|
import ora from "ora";
|
|
176
|
+
import { writeFileSync, mkdirSync } from "fs";
|
|
177
|
+
import { resolve } from "path";
|
|
144
178
|
|
|
145
|
-
// src/
|
|
146
|
-
import {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{
|
|
164
|
-
|
|
165
|
-
type: "function",
|
|
166
|
-
inputs: [{ name: "mintAmount", type: "uint256" }],
|
|
167
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
name: "borrow",
|
|
171
|
-
type: "function",
|
|
172
|
-
inputs: [{ name: "borrowAmount", type: "uint256" }],
|
|
173
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
name: "repayBorrow",
|
|
177
|
-
type: "function",
|
|
178
|
-
inputs: [{ name: "repayAmount", type: "uint256" }],
|
|
179
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: "redeemUnderlying",
|
|
183
|
-
type: "function",
|
|
184
|
-
inputs: [{ name: "redeemAmount", type: "uint256" }],
|
|
185
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
186
|
-
}
|
|
187
|
-
];
|
|
188
|
-
var COMPTROLLER_ABI = [
|
|
189
|
-
{
|
|
190
|
-
name: "enterMarkets",
|
|
191
|
-
type: "function",
|
|
192
|
-
inputs: [{ name: "mTokens", type: "address[]" }],
|
|
193
|
-
outputs: [{ name: "", type: "uint256[]" }]
|
|
179
|
+
// src/lib/clone.ts
|
|
180
|
+
import { concat } from "viem";
|
|
181
|
+
async function cloneTemplate(template) {
|
|
182
|
+
const creationCode = concat([
|
|
183
|
+
"0x3d602d80600a3d3981f3363d3d373d3d3d363d73",
|
|
184
|
+
template,
|
|
185
|
+
"0x5af43d82803e903d91602b57fd5bf3"
|
|
186
|
+
]);
|
|
187
|
+
const wallet = getWalletClient();
|
|
188
|
+
const account = getAccount();
|
|
189
|
+
const chain = getChain();
|
|
190
|
+
const hash = await wallet.sendTransaction({
|
|
191
|
+
account,
|
|
192
|
+
chain,
|
|
193
|
+
data: creationCode,
|
|
194
|
+
value: 0n
|
|
195
|
+
});
|
|
196
|
+
const receipt = await getPublicClient().waitForTransactionReceipt({ hash });
|
|
197
|
+
if (!receipt.contractAddress) {
|
|
198
|
+
throw new Error(`Clone deployment failed \u2014 no contract address in receipt (tx: ${hash})`);
|
|
194
199
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
200
|
+
return { clone: receipt.contractAddress, hash };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/lib/batch.ts
|
|
204
|
+
function formatBatch(calls) {
|
|
205
|
+
return calls.map((call, i) => {
|
|
206
|
+
const selector = call.data.slice(0, 10);
|
|
207
|
+
return ` ${i + 1}. ${call.target} :: ${selector}... (${call.value > 0n ? call.value + " wei" : "no value"})`;
|
|
208
|
+
}).join("\n");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/strategies/moonwell-supply-template.ts
|
|
212
|
+
import { encodeAbiParameters, encodeFunctionData } from "viem";
|
|
213
|
+
function buildInitData(underlying, mToken, supplyAmount, minRedeemAmount) {
|
|
214
|
+
return encodeAbiParameters(
|
|
215
|
+
[
|
|
216
|
+
{ type: "address" },
|
|
217
|
+
{ type: "address" },
|
|
218
|
+
{ type: "uint256" },
|
|
219
|
+
{ type: "uint256" }
|
|
214
220
|
],
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
if (MOONWELL().mWETH === ZERO || MOONWELL().mUSDC === ZERO || MOONWELL().COMPTROLLER === ZERO) {
|
|
221
|
-
throw new Error("Moonwell is not deployed on this network \u2014 levered swap requires Moonwell lending markets");
|
|
222
|
-
}
|
|
223
|
-
const collateral = parseEther(config.collateralAmount);
|
|
224
|
-
const borrow = parseUnits(config.borrowAmount, borrowDecimals);
|
|
225
|
-
const calls = [
|
|
226
|
-
// 1. Approve mWETH to pull WETH from executor
|
|
221
|
+
[underlying, mToken, supplyAmount, minRedeemAmount]
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function buildExecuteCalls(clone, underlying, supplyAmount) {
|
|
225
|
+
return [
|
|
227
226
|
{
|
|
228
|
-
target:
|
|
227
|
+
target: underlying,
|
|
229
228
|
data: encodeFunctionData({
|
|
230
|
-
abi:
|
|
229
|
+
abi: ERC20_ABI,
|
|
231
230
|
functionName: "approve",
|
|
232
|
-
args: [
|
|
231
|
+
args: [clone, supplyAmount]
|
|
233
232
|
}),
|
|
234
233
|
value: 0n
|
|
235
234
|
},
|
|
236
|
-
// 2. Deposit WETH as collateral (mint mWETH tokens)
|
|
237
235
|
{
|
|
238
|
-
target:
|
|
236
|
+
target: clone,
|
|
239
237
|
data: encodeFunctionData({
|
|
240
|
-
abi:
|
|
241
|
-
functionName: "
|
|
242
|
-
args: [collateral]
|
|
238
|
+
abi: BASE_STRATEGY_ABI,
|
|
239
|
+
functionName: "execute"
|
|
243
240
|
}),
|
|
244
241
|
value: 0n
|
|
245
|
-
}
|
|
246
|
-
|
|
242
|
+
}
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
function buildSettleCalls(clone) {
|
|
246
|
+
return [
|
|
247
247
|
{
|
|
248
|
-
target:
|
|
248
|
+
target: clone,
|
|
249
249
|
data: encodeFunctionData({
|
|
250
|
-
abi:
|
|
251
|
-
functionName: "
|
|
252
|
-
args: [[MOONWELL().mWETH]]
|
|
250
|
+
abi: BASE_STRATEGY_ABI,
|
|
251
|
+
functionName: "settle"
|
|
253
252
|
}),
|
|
254
253
|
value: 0n
|
|
255
|
-
}
|
|
256
|
-
|
|
254
|
+
}
|
|
255
|
+
];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/strategies/venice-inference-template.ts
|
|
259
|
+
import { encodeAbiParameters as encodeAbiParameters2, encodeFunctionData as encodeFunctionData2 } from "viem";
|
|
260
|
+
var INIT_PARAMS_TYPES = [
|
|
261
|
+
{
|
|
262
|
+
type: "tuple",
|
|
263
|
+
components: [
|
|
264
|
+
{ name: "asset", type: "address" },
|
|
265
|
+
{ name: "weth", type: "address" },
|
|
266
|
+
{ name: "vvv", type: "address" },
|
|
267
|
+
{ name: "sVVV", type: "address" },
|
|
268
|
+
{ name: "aeroRouter", type: "address" },
|
|
269
|
+
{ name: "aeroFactory", type: "address" },
|
|
270
|
+
{ name: "agent", type: "address" },
|
|
271
|
+
{ name: "assetAmount", type: "uint256" },
|
|
272
|
+
{ name: "minVVV", type: "uint256" },
|
|
273
|
+
{ name: "deadlineOffset", type: "uint256" },
|
|
274
|
+
{ name: "singleHop", type: "bool" }
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
];
|
|
278
|
+
function buildInitData2(params) {
|
|
279
|
+
return encodeAbiParameters2(INIT_PARAMS_TYPES, [params]);
|
|
280
|
+
}
|
|
281
|
+
function buildExecuteCalls2(clone, asset, assetAmount) {
|
|
282
|
+
return [
|
|
257
283
|
{
|
|
258
|
-
target:
|
|
259
|
-
data:
|
|
260
|
-
abi:
|
|
261
|
-
functionName: "
|
|
262
|
-
args: [
|
|
284
|
+
target: asset,
|
|
285
|
+
data: encodeFunctionData2({
|
|
286
|
+
abi: ERC20_ABI,
|
|
287
|
+
functionName: "approve",
|
|
288
|
+
args: [clone, assetAmount]
|
|
263
289
|
}),
|
|
264
290
|
value: 0n
|
|
265
291
|
},
|
|
266
|
-
// 5. Approve SwapRouter to pull borrowed USDC
|
|
267
292
|
{
|
|
268
|
-
target:
|
|
269
|
-
data:
|
|
270
|
-
abi:
|
|
271
|
-
functionName: "
|
|
272
|
-
args: [UNISWAP().SWAP_ROUTER, borrow]
|
|
293
|
+
target: clone,
|
|
294
|
+
data: encodeFunctionData2({
|
|
295
|
+
abi: BASE_STRATEGY_ABI,
|
|
296
|
+
functionName: "execute"
|
|
273
297
|
}),
|
|
274
298
|
value: 0n
|
|
275
|
-
}
|
|
276
|
-
|
|
299
|
+
}
|
|
300
|
+
];
|
|
301
|
+
}
|
|
302
|
+
function buildSettleCalls2(clone) {
|
|
303
|
+
return [
|
|
277
304
|
{
|
|
278
|
-
target:
|
|
279
|
-
data:
|
|
280
|
-
abi:
|
|
281
|
-
functionName: "
|
|
282
|
-
args: [
|
|
283
|
-
{
|
|
284
|
-
tokenIn: TOKENS().USDC,
|
|
285
|
-
tokenOut: config.targetToken,
|
|
286
|
-
fee: config.fee,
|
|
287
|
-
recipient: vaultAddress,
|
|
288
|
-
// Tokens stay in vault (delegatecall)
|
|
289
|
-
amountIn: borrow,
|
|
290
|
-
amountOutMinimum,
|
|
291
|
-
sqrtPriceLimitX96: 0n
|
|
292
|
-
}
|
|
293
|
-
]
|
|
305
|
+
target: clone,
|
|
306
|
+
data: encodeFunctionData2({
|
|
307
|
+
abi: BASE_STRATEGY_ABI,
|
|
308
|
+
functionName: "settle"
|
|
294
309
|
}),
|
|
295
310
|
value: 0n
|
|
296
311
|
}
|
|
297
312
|
];
|
|
298
|
-
return calls;
|
|
299
313
|
}
|
|
300
314
|
|
|
301
|
-
// src/
|
|
302
|
-
import {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
315
|
+
// src/strategies/aerodrome-lp-template.ts
|
|
316
|
+
import { encodeAbiParameters as encodeAbiParameters3, encodeFunctionData as encodeFunctionData3 } from "viem";
|
|
317
|
+
var INIT_PARAMS_TYPES2 = [
|
|
318
|
+
{
|
|
319
|
+
type: "tuple",
|
|
320
|
+
components: [
|
|
321
|
+
{ name: "tokenA", type: "address" },
|
|
322
|
+
{ name: "tokenB", type: "address" },
|
|
323
|
+
{ name: "stable", type: "bool" },
|
|
324
|
+
{ name: "factory", type: "address" },
|
|
325
|
+
{ name: "router", type: "address" },
|
|
326
|
+
{ name: "gauge", type: "address" },
|
|
327
|
+
{ name: "lpToken", type: "address" },
|
|
328
|
+
{ name: "amountADesired", type: "uint256" },
|
|
329
|
+
{ name: "amountBDesired", type: "uint256" },
|
|
330
|
+
{ name: "amountAMin", type: "uint256" },
|
|
331
|
+
{ name: "amountBMin", type: "uint256" },
|
|
332
|
+
{ name: "minAmountAOut", type: "uint256" },
|
|
333
|
+
{ name: "minAmountBOut", type: "uint256" }
|
|
316
334
|
]
|
|
317
|
-
});
|
|
318
|
-
const { data } = await client.call({
|
|
319
|
-
to: UNISWAP().QUOTER_V2,
|
|
320
|
-
data: calldata
|
|
321
|
-
});
|
|
322
|
-
if (!data) {
|
|
323
|
-
throw new Error("Quoter returned no data \u2014 pool may not exist for this pair/fee");
|
|
324
335
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
data
|
|
329
|
-
});
|
|
330
|
-
return { amountOut, sqrtPriceX96After, gasEstimate };
|
|
331
|
-
}
|
|
332
|
-
function applySlippage(amountOut, slippageBps) {
|
|
333
|
-
return amountOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
336
|
+
];
|
|
337
|
+
function buildInitData3(params) {
|
|
338
|
+
return encodeAbiParameters3(INIT_PARAMS_TYPES2, [params]);
|
|
334
339
|
}
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
function buildExecuteCalls3(clone, tokenA, amountA, tokenB, amountB) {
|
|
341
|
+
return [
|
|
342
|
+
{
|
|
343
|
+
target: tokenA,
|
|
344
|
+
data: encodeFunctionData3({
|
|
345
|
+
abi: ERC20_ABI,
|
|
346
|
+
functionName: "approve",
|
|
347
|
+
args: [clone, amountA]
|
|
348
|
+
}),
|
|
349
|
+
value: 0n
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
target: tokenB,
|
|
353
|
+
data: encodeFunctionData3({
|
|
354
|
+
abi: ERC20_ABI,
|
|
355
|
+
functionName: "approve",
|
|
356
|
+
args: [clone, amountB]
|
|
357
|
+
}),
|
|
358
|
+
value: 0n
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
target: clone,
|
|
362
|
+
data: encodeFunctionData3({
|
|
363
|
+
abi: BASE_STRATEGY_ABI,
|
|
364
|
+
functionName: "execute"
|
|
365
|
+
}),
|
|
366
|
+
value: 0n
|
|
344
367
|
}
|
|
345
|
-
|
|
346
|
-
return concat(parts);
|
|
347
|
-
}
|
|
348
|
-
async function getMultiHopQuote(params) {
|
|
349
|
-
const client = getPublicClient();
|
|
350
|
-
const calldata = encodeFunctionData2({
|
|
351
|
-
abi: UNISWAP_QUOTER_V2_ABI,
|
|
352
|
-
functionName: "quoteExactInput",
|
|
353
|
-
args: [params.path, params.amountIn]
|
|
354
|
-
});
|
|
355
|
-
const { data } = await client.call({
|
|
356
|
-
to: UNISWAP().QUOTER_V2,
|
|
357
|
-
data: calldata
|
|
358
|
-
});
|
|
359
|
-
if (!data) {
|
|
360
|
-
throw new Error("Quoter returned no data \u2014 pool may not exist for this path");
|
|
361
|
-
}
|
|
362
|
-
const [amountOut, , , gasEstimate] = decodeFunctionResult({
|
|
363
|
-
abi: UNISWAP_QUOTER_V2_ABI,
|
|
364
|
-
functionName: "quoteExactInput",
|
|
365
|
-
data
|
|
366
|
-
});
|
|
367
|
-
return { amountOut, sqrtPriceX96After: 0n, gasEstimate };
|
|
368
|
+
];
|
|
368
369
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
370
|
+
function buildSettleCalls3(clone) {
|
|
371
|
+
return [
|
|
372
|
+
{
|
|
373
|
+
target: clone,
|
|
374
|
+
data: encodeFunctionData3({
|
|
375
|
+
abi: BASE_STRATEGY_ABI,
|
|
376
|
+
functionName: "settle"
|
|
377
|
+
}),
|
|
378
|
+
value: 0n
|
|
379
|
+
}
|
|
380
|
+
];
|
|
376
381
|
}
|
|
377
382
|
|
|
378
|
-
// src/commands/strategy-
|
|
379
|
-
var
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
383
|
+
// src/commands/strategy-template.ts
|
|
384
|
+
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
385
|
+
var TEMPLATES = [
|
|
386
|
+
{
|
|
387
|
+
name: "Moonwell Supply",
|
|
388
|
+
key: "moonwell-supply",
|
|
389
|
+
description: "Supply tokens to Moonwell lending market, earn yield",
|
|
390
|
+
addressKey: "MOONWELL_SUPPLY"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "Aerodrome LP",
|
|
394
|
+
key: "aerodrome-lp",
|
|
395
|
+
description: "Provide liquidity on Aerodrome DEX + optional gauge staking",
|
|
396
|
+
addressKey: "AERODROME_LP"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
name: "Venice Inference",
|
|
400
|
+
key: "venice-inference",
|
|
401
|
+
description: "Stake VVV for sVVV \u2014 Venice private AI inference",
|
|
402
|
+
addressKey: "VENICE_INFERENCE"
|
|
403
|
+
}
|
|
404
|
+
];
|
|
405
|
+
function resolveTemplate(key) {
|
|
406
|
+
const def = TEMPLATES.find((t) => t.key === key);
|
|
407
|
+
if (!def) {
|
|
408
|
+
console.error(chalk.red(`Unknown template: ${key}`));
|
|
409
|
+
console.error(chalk.dim(`Available: ${TEMPLATES.map((t) => t.key).join(", ")}`));
|
|
384
410
|
process.exit(1);
|
|
385
411
|
}
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
console.error(chalk.red(`Invalid fee tier: ${opts.fee}. Valid: ${VALID_FEES.join(", ")}`));
|
|
412
|
+
const address = STRATEGY_TEMPLATES()[def.addressKey];
|
|
413
|
+
if (address === ZERO) {
|
|
414
|
+
console.error(chalk.red(`Template "${def.name}" not deployed on this network.`));
|
|
390
415
|
process.exit(1);
|
|
391
416
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
417
|
+
return { def, address };
|
|
418
|
+
}
|
|
419
|
+
async function buildInitDataForTemplate(templateKey, opts, vault) {
|
|
420
|
+
if (templateKey === "moonwell-supply") {
|
|
421
|
+
if (!opts.amount) {
|
|
422
|
+
console.error(chalk.red("--amount is required for moonwell-supply template"));
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
const token = opts.token || "USDC";
|
|
426
|
+
const underlying = resolveToken(token);
|
|
427
|
+
const mToken = resolveMToken(token);
|
|
428
|
+
const decimals = token.toUpperCase() === "USDC" ? 6 : 18;
|
|
429
|
+
const supplyAmount = parseUnits(opts.amount, decimals);
|
|
430
|
+
const minRedeem = parseUnits(opts.minRedeem || opts.amount, decimals);
|
|
431
|
+
return {
|
|
432
|
+
initData: buildInitData(underlying, mToken, supplyAmount, minRedeem),
|
|
433
|
+
asset: underlying,
|
|
434
|
+
assetAmount: supplyAmount
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
if (templateKey === "venice-inference") {
|
|
438
|
+
if (!opts.amount) {
|
|
439
|
+
console.error(chalk.red("--amount is required for venice-inference template"));
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
const assetSymbol = opts.asset || "USDC";
|
|
443
|
+
const asset = resolveToken(assetSymbol);
|
|
444
|
+
const vvv = VENICE().VVV;
|
|
445
|
+
const isDirect = asset.toLowerCase() === vvv.toLowerCase();
|
|
446
|
+
const decimals = assetSymbol.toUpperCase() === "USDC" ? 6 : 18;
|
|
447
|
+
const assetAmount = parseUnits(opts.amount, decimals);
|
|
448
|
+
const agent = opts.agent || getAccount().address;
|
|
449
|
+
const params = {
|
|
450
|
+
asset,
|
|
451
|
+
weth: isDirect ? ZERO : TOKENS().WETH,
|
|
452
|
+
vvv,
|
|
453
|
+
sVVV: VENICE().STAKING,
|
|
454
|
+
aeroRouter: isDirect ? ZERO : AERODROME().ROUTER,
|
|
455
|
+
aeroFactory: isDirect ? ZERO : AERODROME().FACTORY,
|
|
456
|
+
agent,
|
|
457
|
+
assetAmount,
|
|
458
|
+
minVVV: isDirect ? 0n : parseUnits(opts.minVvv || "0", 18),
|
|
459
|
+
deadlineOffset: 300n,
|
|
460
|
+
singleHop: !!opts.singleHop
|
|
461
|
+
};
|
|
462
|
+
return {
|
|
463
|
+
initData: buildInitData2(params),
|
|
464
|
+
asset,
|
|
465
|
+
assetAmount
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
if (templateKey === "aerodrome-lp") {
|
|
469
|
+
for (const flag of ["tokenA", "tokenB", "amountA", "amountB", "lpToken"]) {
|
|
470
|
+
if (!opts[flag]) {
|
|
471
|
+
console.error(chalk.red(`--${flag.replace(/([A-Z])/g, "-$1").toLowerCase()} is required for aerodrome-lp template`));
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const tokenA = opts.tokenA;
|
|
476
|
+
const tokenB = opts.tokenB;
|
|
477
|
+
const publicClient = getPublicClient();
|
|
478
|
+
const [decimalsA, decimalsB] = await Promise.all([
|
|
479
|
+
publicClient.readContract({ address: tokenA, abi: erc20Abi, functionName: "decimals" }),
|
|
480
|
+
publicClient.readContract({ address: tokenB, abi: erc20Abi, functionName: "decimals" })
|
|
408
481
|
]);
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
482
|
+
const amountA = parseUnits(opts.amountA, decimalsA);
|
|
483
|
+
const amountB = parseUnits(opts.amountB, decimalsB);
|
|
484
|
+
const minAOut = parseUnits(opts.minAOut || "0", decimalsA);
|
|
485
|
+
const minBOut = parseUnits(opts.minBOut || "0", decimalsB);
|
|
486
|
+
const params = {
|
|
487
|
+
tokenA,
|
|
488
|
+
tokenB,
|
|
489
|
+
stable: !!opts.stable,
|
|
490
|
+
factory: AERODROME().FACTORY,
|
|
491
|
+
router: AERODROME().ROUTER,
|
|
492
|
+
gauge: opts.gauge || ZERO,
|
|
493
|
+
lpToken: opts.lpToken,
|
|
494
|
+
amountADesired: amountA,
|
|
495
|
+
amountBDesired: amountB,
|
|
496
|
+
amountAMin: amountA,
|
|
497
|
+
// use desired as min for now
|
|
498
|
+
amountBMin: amountB,
|
|
499
|
+
minAmountAOut: minAOut,
|
|
500
|
+
minAmountBOut: minBOut
|
|
501
|
+
};
|
|
502
|
+
return {
|
|
503
|
+
initData: buildInitData3(params),
|
|
504
|
+
asset: tokenA,
|
|
505
|
+
assetAmount: amountA,
|
|
506
|
+
extraApprovals: [{ token: tokenB, amount: amountB }]
|
|
507
|
+
};
|
|
412
508
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
console.log(` Vault: ${vaultAddress}`);
|
|
422
|
-
console.log();
|
|
423
|
-
const spinner = ora("Fetching Uniswap quote...").start();
|
|
424
|
-
let amountOut;
|
|
425
|
-
let minOut;
|
|
426
|
-
try {
|
|
427
|
-
const borrowAmount = parseUnits2(opts.borrow, borrowDecimals);
|
|
428
|
-
const quote = await getQuote({
|
|
429
|
-
tokenIn: TOKENS().USDC,
|
|
430
|
-
tokenOut: targetToken,
|
|
431
|
-
amountIn: borrowAmount,
|
|
432
|
-
fee: feeTier
|
|
433
|
-
});
|
|
434
|
-
amountOut = quote.amountOut;
|
|
435
|
-
minOut = applySlippage(amountOut, slippageBps);
|
|
436
|
-
spinner.succeed(
|
|
437
|
-
`Quote: ${formatUnits(amountOut, targetDecimals)} tokens (min: ${formatUnits(minOut, targetDecimals)}, gas est: ${quote.gasEstimate})`
|
|
438
|
-
);
|
|
439
|
-
} catch (err) {
|
|
440
|
-
spinner.fail("Failed to fetch quote");
|
|
441
|
-
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
442
|
-
process.exit(1);
|
|
509
|
+
throw new Error(`No init builder for template: ${templateKey}`);
|
|
510
|
+
}
|
|
511
|
+
function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraApprovals) {
|
|
512
|
+
if (templateKey === "moonwell-supply") {
|
|
513
|
+
return {
|
|
514
|
+
executeCalls: buildExecuteCalls(clone, asset, assetAmount),
|
|
515
|
+
settleCalls: buildSettleCalls(clone)
|
|
516
|
+
};
|
|
443
517
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
518
|
+
if (templateKey === "venice-inference") {
|
|
519
|
+
return {
|
|
520
|
+
executeCalls: buildExecuteCalls2(clone, asset, assetAmount),
|
|
521
|
+
settleCalls: buildSettleCalls2(clone)
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
if (templateKey === "aerodrome-lp") {
|
|
525
|
+
const tokenB = extraApprovals?.[0]?.token ?? ZERO;
|
|
526
|
+
const amountB = extraApprovals?.[0]?.amount ?? 0n;
|
|
527
|
+
return {
|
|
528
|
+
executeCalls: buildExecuteCalls3(clone, asset, assetAmount, tokenB, amountB),
|
|
529
|
+
settleCalls: buildSettleCalls3(clone)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
throw new Error(`No call builder for template: ${templateKey}`);
|
|
533
|
+
}
|
|
534
|
+
function resolveToken(symbolOrAddress) {
|
|
535
|
+
if (isAddress(symbolOrAddress)) return symbolOrAddress;
|
|
536
|
+
const upper = symbolOrAddress.toUpperCase();
|
|
537
|
+
const tokens = TOKENS();
|
|
538
|
+
const tokenMap = {
|
|
539
|
+
USDC: tokens.USDC,
|
|
540
|
+
WETH: tokens.WETH,
|
|
541
|
+
DAI: tokens.DAI,
|
|
542
|
+
AERO: tokens.AERO,
|
|
543
|
+
VVV: VENICE().VVV
|
|
454
544
|
};
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
console.log();
|
|
460
|
-
if (!opts.execute) {
|
|
461
|
-
console.log();
|
|
462
|
-
console.log(chalk.yellow("Dry run complete. Add --execute to submit on-chain."));
|
|
463
|
-
console.log(chalk.dim(" Prerequisite: send WETH to vault before executing."));
|
|
464
|
-
return;
|
|
545
|
+
const addr = tokenMap[upper];
|
|
546
|
+
if (!addr || addr === ZERO) {
|
|
547
|
+
console.error(chalk.red(`Unknown token: ${symbolOrAddress}`));
|
|
548
|
+
process.exit(1);
|
|
465
549
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
550
|
+
return addr;
|
|
551
|
+
}
|
|
552
|
+
function resolveMToken(tokenSymbol) {
|
|
553
|
+
const upper = tokenSymbol.toUpperCase();
|
|
554
|
+
const moonwell = MOONWELL();
|
|
555
|
+
const mTokenMap = {
|
|
556
|
+
USDC: moonwell.mUSDC,
|
|
557
|
+
WETH: moonwell.mWETH
|
|
558
|
+
};
|
|
559
|
+
const addr = mTokenMap[upper];
|
|
560
|
+
if (!addr || addr === ZERO) {
|
|
561
|
+
console.error(chalk.red(`No Moonwell market for: ${tokenSymbol}`));
|
|
474
562
|
process.exit(1);
|
|
475
563
|
}
|
|
564
|
+
return addr;
|
|
565
|
+
}
|
|
566
|
+
function serializeCalls(calls) {
|
|
567
|
+
return JSON.stringify(
|
|
568
|
+
calls.map((c) => ({
|
|
569
|
+
target: c.target,
|
|
570
|
+
data: c.data,
|
|
571
|
+
value: c.value.toString()
|
|
572
|
+
})),
|
|
573
|
+
null,
|
|
574
|
+
2
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
function registerStrategyTemplateCommands(strategy2) {
|
|
578
|
+
strategy2.command("list").description("List available strategy templates").action(() => {
|
|
579
|
+
const templates = STRATEGY_TEMPLATES();
|
|
580
|
+
console.log();
|
|
581
|
+
console.log(chalk.bold("Strategy Templates"));
|
|
582
|
+
console.log(chalk.dim("\u2500".repeat(60)));
|
|
583
|
+
for (const t of TEMPLATES) {
|
|
584
|
+
const addr = templates[t.addressKey];
|
|
585
|
+
const deployed = addr !== ZERO;
|
|
586
|
+
console.log();
|
|
587
|
+
console.log(` ${chalk.bold(t.name)} (${chalk.cyan(t.key)})`);
|
|
588
|
+
console.log(` ${t.description}`);
|
|
589
|
+
console.log(` Template: ${deployed ? chalk.green(addr) : chalk.red("not deployed")}`);
|
|
590
|
+
}
|
|
591
|
+
console.log();
|
|
592
|
+
console.log(chalk.dim("Clone a template: sherwood strategy clone <template> --vault <addr> ..."));
|
|
593
|
+
console.log(chalk.dim("Full proposal: sherwood strategy propose <template> --vault <addr> ..."));
|
|
594
|
+
console.log();
|
|
595
|
+
});
|
|
596
|
+
strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference").requiredOption("--vault <address>", "Vault address").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").action(async (templateKey, opts) => {
|
|
597
|
+
const vault = opts.vault;
|
|
598
|
+
if (!isAddress(vault)) {
|
|
599
|
+
console.error(chalk.red("Invalid vault address"));
|
|
600
|
+
process.exit(1);
|
|
601
|
+
}
|
|
602
|
+
const { def, address: templateAddr } = resolveTemplate(templateKey);
|
|
603
|
+
const cloneSpinner = ora(`Cloning ${def.name} template...`).start();
|
|
604
|
+
let clone;
|
|
605
|
+
let cloneHash;
|
|
606
|
+
try {
|
|
607
|
+
const result = await cloneTemplate(templateAddr);
|
|
608
|
+
clone = result.clone;
|
|
609
|
+
cloneHash = result.hash;
|
|
610
|
+
cloneSpinner.succeed(`Cloned: ${chalk.green(clone)}`);
|
|
611
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(cloneHash)}`));
|
|
612
|
+
} catch (err) {
|
|
613
|
+
cloneSpinner.fail("Clone failed");
|
|
614
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
615
|
+
process.exit(1);
|
|
616
|
+
}
|
|
617
|
+
const initSpinner = ora("Initializing strategy...").start();
|
|
618
|
+
try {
|
|
619
|
+
const { initData } = await buildInitDataForTemplate(templateKey, opts, vault);
|
|
620
|
+
const account = getAccount();
|
|
621
|
+
const wallet = getWalletClient();
|
|
622
|
+
const initHash = await wallet.writeContract({
|
|
623
|
+
account,
|
|
624
|
+
chain: getChain(),
|
|
625
|
+
address: clone,
|
|
626
|
+
abi: BASE_STRATEGY_ABI,
|
|
627
|
+
functionName: "initialize",
|
|
628
|
+
args: [vault, account.address, initData]
|
|
629
|
+
});
|
|
630
|
+
await getPublicClient().waitForTransactionReceipt({ hash: initHash });
|
|
631
|
+
initSpinner.succeed("Initialized");
|
|
632
|
+
} catch (err) {
|
|
633
|
+
initSpinner.fail("Initialize failed");
|
|
634
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
635
|
+
process.exit(1);
|
|
636
|
+
}
|
|
637
|
+
console.log();
|
|
638
|
+
console.log(chalk.bold("Strategy clone ready:"), chalk.green(clone));
|
|
639
|
+
console.log(chalk.dim("Use this address in your proposal batch calls."));
|
|
640
|
+
console.log();
|
|
641
|
+
});
|
|
642
|
+
strategy2.command("propose").description("Clone + init + build calls + submit governance proposal (all-in-one)").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference").requiredOption("--vault <address>", "Vault address").option("--write-calls <dir>", "Write execute/settle JSON to directory (skip proposal submission)").option("--name <name>", "Proposal name").option("--description <text>", "Proposal description").option("--performance-fee <bps>", "Agent fee in bps").option("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").action(async (templateKey, opts) => {
|
|
643
|
+
const vault = opts.vault;
|
|
644
|
+
if (!isAddress(vault)) {
|
|
645
|
+
console.error(chalk.red("Invalid vault address"));
|
|
646
|
+
process.exit(1);
|
|
647
|
+
}
|
|
648
|
+
const { def, address: templateAddr } = resolveTemplate(templateKey);
|
|
649
|
+
const cloneSpinner = ora(`Cloning ${def.name} template...`).start();
|
|
650
|
+
let clone;
|
|
651
|
+
try {
|
|
652
|
+
const result = await cloneTemplate(templateAddr);
|
|
653
|
+
clone = result.clone;
|
|
654
|
+
cloneSpinner.succeed(`Cloned: ${chalk.green(clone)}`);
|
|
655
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(result.hash)}`));
|
|
656
|
+
} catch (err) {
|
|
657
|
+
cloneSpinner.fail("Clone failed");
|
|
658
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
659
|
+
process.exit(1);
|
|
660
|
+
}
|
|
661
|
+
const initSpinner = ora("Initializing strategy...").start();
|
|
662
|
+
let asset;
|
|
663
|
+
let assetAmount;
|
|
664
|
+
let extraApprovals;
|
|
665
|
+
try {
|
|
666
|
+
const built = await buildInitDataForTemplate(templateKey, opts, vault);
|
|
667
|
+
asset = built.asset;
|
|
668
|
+
assetAmount = built.assetAmount;
|
|
669
|
+
extraApprovals = built.extraApprovals;
|
|
670
|
+
const account2 = getAccount();
|
|
671
|
+
const wallet = getWalletClient();
|
|
672
|
+
const initHash = await wallet.writeContract({
|
|
673
|
+
account: account2,
|
|
674
|
+
chain: getChain(),
|
|
675
|
+
address: clone,
|
|
676
|
+
abi: BASE_STRATEGY_ABI,
|
|
677
|
+
functionName: "initialize",
|
|
678
|
+
args: [vault, account2.address, built.initData]
|
|
679
|
+
});
|
|
680
|
+
await getPublicClient().waitForTransactionReceipt({ hash: initHash });
|
|
681
|
+
initSpinner.succeed("Initialized");
|
|
682
|
+
} catch (err) {
|
|
683
|
+
initSpinner.fail("Initialize failed");
|
|
684
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
685
|
+
process.exit(1);
|
|
686
|
+
}
|
|
687
|
+
const { executeCalls, settleCalls } = buildCallsForTemplate(
|
|
688
|
+
templateKey,
|
|
689
|
+
clone,
|
|
690
|
+
asset,
|
|
691
|
+
assetAmount,
|
|
692
|
+
extraApprovals
|
|
693
|
+
);
|
|
694
|
+
console.log();
|
|
695
|
+
console.log(chalk.bold(`Execute calls (${executeCalls.length}):`));
|
|
696
|
+
console.log(formatBatch(executeCalls));
|
|
697
|
+
console.log(chalk.bold(`Settle calls (${settleCalls.length}):`));
|
|
698
|
+
console.log(formatBatch(settleCalls));
|
|
699
|
+
if (opts.writeCalls) {
|
|
700
|
+
const dir = resolve(opts.writeCalls);
|
|
701
|
+
mkdirSync(dir, { recursive: true });
|
|
702
|
+
const execPath = resolve(dir, "execute.json");
|
|
703
|
+
const settlePath = resolve(dir, "settle.json");
|
|
704
|
+
writeFileSync(execPath, serializeCalls(executeCalls));
|
|
705
|
+
writeFileSync(settlePath, serializeCalls(settleCalls));
|
|
706
|
+
console.log();
|
|
707
|
+
console.log(chalk.green(`Execute calls: ${execPath}`));
|
|
708
|
+
console.log(chalk.green(`Settle calls: ${settlePath}`));
|
|
709
|
+
console.log(chalk.green(`Clone address: ${clone}`));
|
|
710
|
+
console.log();
|
|
711
|
+
console.log(chalk.dim("Submit with:"));
|
|
712
|
+
console.log(chalk.dim(` sherwood proposal create \\`));
|
|
713
|
+
console.log(chalk.dim(` --vault ${vault} \\`));
|
|
714
|
+
console.log(chalk.dim(` --name "..." --description "..." \\`));
|
|
715
|
+
console.log(chalk.dim(` --performance-fee 0 --duration 7d \\`));
|
|
716
|
+
console.log(chalk.dim(` --execute-calls ${execPath} \\`));
|
|
717
|
+
console.log(chalk.dim(` --settle-calls ${settlePath}`));
|
|
718
|
+
if (templateKey === "venice-inference") {
|
|
719
|
+
console.log();
|
|
720
|
+
console.log(chalk.yellow("Reminder: agent must pre-approve sVVV clawback:"));
|
|
721
|
+
console.log(chalk.yellow(` sVVV.approve(${clone}, <amount>)`));
|
|
722
|
+
}
|
|
723
|
+
console.log();
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
if (!opts.name || !opts.performanceFee || !opts.duration) {
|
|
727
|
+
console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
|
|
728
|
+
process.exit(1);
|
|
729
|
+
}
|
|
730
|
+
const { propose: propose2 } = await import("./governor-P6YV4YR7.js");
|
|
731
|
+
const { pinJSON } = await import("./ipfs-6XVOOHSR.js");
|
|
732
|
+
const { parseDuration: parseDuration2 } = await import("./governor-P6YV4YR7.js");
|
|
733
|
+
const performanceFeeBps = BigInt(opts.performanceFee);
|
|
734
|
+
if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
|
|
735
|
+
console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
const strategyDuration = parseDuration2(opts.duration);
|
|
739
|
+
const account = getAccount();
|
|
740
|
+
const metaSpinner = ora("Pinning metadata to IPFS...").start();
|
|
741
|
+
let metadataURI;
|
|
742
|
+
try {
|
|
743
|
+
const metadata = {
|
|
744
|
+
name: opts.name,
|
|
745
|
+
description: opts.description || "",
|
|
746
|
+
proposer: account.address,
|
|
747
|
+
vault,
|
|
748
|
+
strategyClone: clone,
|
|
749
|
+
template: def.key,
|
|
750
|
+
performanceFeeBps: Number(performanceFeeBps),
|
|
751
|
+
strategyDuration: Number(strategyDuration),
|
|
752
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
753
|
+
};
|
|
754
|
+
metadataURI = await pinJSON(metadata, opts.name);
|
|
755
|
+
metaSpinner.succeed(`Metadata pinned: ${metadataURI}`);
|
|
756
|
+
} catch (err) {
|
|
757
|
+
metaSpinner.fail("IPFS pin failed");
|
|
758
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
759
|
+
process.exit(1);
|
|
760
|
+
}
|
|
761
|
+
const proposeSpinner = ora("Submitting proposal...").start();
|
|
762
|
+
try {
|
|
763
|
+
const { hash, proposalId } = await propose2(
|
|
764
|
+
vault,
|
|
765
|
+
metadataURI,
|
|
766
|
+
performanceFeeBps,
|
|
767
|
+
strategyDuration,
|
|
768
|
+
executeCalls,
|
|
769
|
+
settleCalls
|
|
770
|
+
);
|
|
771
|
+
proposeSpinner.succeed(`Proposal #${proposalId} created`);
|
|
772
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(hash)}`));
|
|
773
|
+
console.log(chalk.dim(` Clone: ${clone}`));
|
|
774
|
+
} catch (err) {
|
|
775
|
+
proposeSpinner.fail("Proposal failed");
|
|
776
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
777
|
+
process.exit(1);
|
|
778
|
+
}
|
|
779
|
+
if (templateKey === "venice-inference") {
|
|
780
|
+
console.log();
|
|
781
|
+
console.log(chalk.yellow("Next steps:"));
|
|
782
|
+
console.log(chalk.yellow(` 1. Pre-approve sVVV clawback: sVVV.approve(${clone}, <amount>)`));
|
|
783
|
+
console.log(chalk.yellow(" 2. After execution: sherwood venice provision"));
|
|
784
|
+
console.log(chalk.yellow(" 3. Use inference: sherwood venice infer --model <id> --prompt '...'"));
|
|
785
|
+
}
|
|
786
|
+
console.log();
|
|
787
|
+
});
|
|
476
788
|
}
|
|
477
789
|
|
|
478
790
|
// src/lib/factory.ts
|
|
@@ -652,74 +964,83 @@ async function getActiveSyndicates2(creator) {
|
|
|
652
964
|
return data.syndicates;
|
|
653
965
|
}
|
|
654
966
|
|
|
655
|
-
// src/
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
chain: getChain(),
|
|
664
|
-
address: getRegistryAddress(),
|
|
665
|
-
abi: STRATEGY_REGISTRY_ABI,
|
|
666
|
-
functionName: "registerStrategy",
|
|
667
|
-
args: [implementation, strategyTypeId, name, metadataURI]
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
async function getStrategy(id) {
|
|
967
|
+
// src/commands/venice.ts
|
|
968
|
+
import { parseUnits as parseUnits4, formatUnits as formatUnits2, isAddress as isAddress2 } from "viem";
|
|
969
|
+
import chalk2 from "chalk";
|
|
970
|
+
import ora2 from "ora";
|
|
971
|
+
|
|
972
|
+
// src/lib/quote.ts
|
|
973
|
+
import { encodeFunctionData as encodeFunctionData4, decodeFunctionResult, concat as concat2, pad, numberToHex } from "viem";
|
|
974
|
+
async function getQuote(params) {
|
|
671
975
|
const client = getPublicClient();
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
976
|
+
const calldata = encodeFunctionData4({
|
|
977
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
978
|
+
functionName: "quoteExactInputSingle",
|
|
979
|
+
args: [
|
|
980
|
+
{
|
|
981
|
+
tokenIn: params.tokenIn,
|
|
982
|
+
tokenOut: params.tokenOut,
|
|
983
|
+
amountIn: params.amountIn,
|
|
984
|
+
fee: params.fee,
|
|
985
|
+
sqrtPriceLimitX96: 0n
|
|
986
|
+
}
|
|
987
|
+
]
|
|
677
988
|
});
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
989
|
+
const { data } = await client.call({
|
|
990
|
+
to: UNISWAP().QUOTER_V2,
|
|
991
|
+
data: calldata
|
|
992
|
+
});
|
|
993
|
+
if (!data) {
|
|
994
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this pair/fee");
|
|
995
|
+
}
|
|
996
|
+
const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({
|
|
997
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
998
|
+
functionName: "quoteExactInputSingle",
|
|
999
|
+
data
|
|
1000
|
+
});
|
|
1001
|
+
return { amountOut, sqrtPriceX96After, gasEstimate };
|
|
687
1002
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
address: registryAddress,
|
|
702
|
-
abi: STRATEGY_REGISTRY_ABI,
|
|
703
|
-
functionName: "strategyCount"
|
|
704
|
-
});
|
|
705
|
-
ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
1003
|
+
function applySlippage(amountOut, slippageBps) {
|
|
1004
|
+
return amountOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
1005
|
+
}
|
|
1006
|
+
function encodeSwapPath(tokens, fees) {
|
|
1007
|
+
if (tokens.length < 2 || fees.length !== tokens.length - 1) {
|
|
1008
|
+
throw new Error("Invalid path: need at least 2 tokens and (tokens-1) fees");
|
|
1009
|
+
}
|
|
1010
|
+
const parts = [];
|
|
1011
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1012
|
+
parts.push(tokens[i].toLowerCase());
|
|
1013
|
+
if (i < fees.length) {
|
|
1014
|
+
parts.push(pad(numberToHex(fees[i]), { size: 3 }));
|
|
1015
|
+
}
|
|
706
1016
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1017
|
+
return concat2(parts);
|
|
1018
|
+
}
|
|
1019
|
+
async function getMultiHopQuote(params) {
|
|
1020
|
+
const client = getPublicClient();
|
|
1021
|
+
const calldata = encodeFunctionData4({
|
|
1022
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1023
|
+
functionName: "quoteExactInput",
|
|
1024
|
+
args: [params.path, params.amountIn]
|
|
1025
|
+
});
|
|
1026
|
+
const { data } = await client.call({
|
|
1027
|
+
to: UNISWAP().QUOTER_V2,
|
|
1028
|
+
data: calldata
|
|
1029
|
+
});
|
|
1030
|
+
if (!data) {
|
|
1031
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this path");
|
|
711
1032
|
}
|
|
712
|
-
|
|
1033
|
+
const [amountOut, , , gasEstimate] = decodeFunctionResult({
|
|
1034
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1035
|
+
functionName: "quoteExactInput",
|
|
1036
|
+
data
|
|
1037
|
+
});
|
|
1038
|
+
return { amountOut, sqrtPriceX96After: 0n, gasEstimate };
|
|
713
1039
|
}
|
|
714
1040
|
|
|
715
|
-
// src/commands/venice.ts
|
|
716
|
-
import { parseUnits as parseUnits5, formatUnits as formatUnits3, isAddress as isAddress2 } from "viem";
|
|
717
|
-
import chalk2 from "chalk";
|
|
718
|
-
import ora2 from "ora";
|
|
719
|
-
|
|
720
1041
|
// src/strategies/venice-fund.ts
|
|
721
|
-
import { encodeFunctionData as
|
|
722
|
-
var
|
|
1042
|
+
import { encodeFunctionData as encodeFunctionData5, parseUnits as parseUnits3 } from "viem";
|
|
1043
|
+
var ERC20_ABI2 = [
|
|
723
1044
|
{
|
|
724
1045
|
name: "approve",
|
|
725
1046
|
type: "function",
|
|
@@ -783,17 +1104,17 @@ var STAKING_ABI = [
|
|
|
783
1104
|
}
|
|
784
1105
|
];
|
|
785
1106
|
function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minVVV, swapPath) {
|
|
786
|
-
const
|
|
787
|
-
if (VENICE().VVV ===
|
|
1107
|
+
const ZERO2 = "0x0000000000000000000000000000000000000000";
|
|
1108
|
+
if (VENICE().VVV === ZERO2 || VENICE().STAKING === ZERO2) {
|
|
788
1109
|
throw new Error("Venice (VVV/sVVV) is not deployed on this network \u2014 venice fund requires Venice staking contracts");
|
|
789
1110
|
}
|
|
790
|
-
const assetAmount =
|
|
1111
|
+
const assetAmount = parseUnits3(config.amount, assetDecimals);
|
|
791
1112
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
792
1113
|
const calls = [];
|
|
793
1114
|
calls.push({
|
|
794
1115
|
target: assetAddress,
|
|
795
|
-
data:
|
|
796
|
-
abi:
|
|
1116
|
+
data: encodeFunctionData5({
|
|
1117
|
+
abi: ERC20_ABI2,
|
|
797
1118
|
functionName: "approve",
|
|
798
1119
|
args: [UNISWAP().SWAP_ROUTER, assetAmount]
|
|
799
1120
|
}),
|
|
@@ -802,7 +1123,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
802
1123
|
if (isWeth) {
|
|
803
1124
|
calls.push({
|
|
804
1125
|
target: UNISWAP().SWAP_ROUTER,
|
|
805
|
-
data:
|
|
1126
|
+
data: encodeFunctionData5({
|
|
806
1127
|
abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
|
|
807
1128
|
functionName: "exactInputSingle",
|
|
808
1129
|
args: [
|
|
@@ -822,7 +1143,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
822
1143
|
} else {
|
|
823
1144
|
calls.push({
|
|
824
1145
|
target: UNISWAP().SWAP_ROUTER,
|
|
825
|
-
data:
|
|
1146
|
+
data: encodeFunctionData5({
|
|
826
1147
|
abi: SWAP_ROUTER_EXACT_INPUT_ABI,
|
|
827
1148
|
functionName: "exactInput",
|
|
828
1149
|
args: [
|
|
@@ -839,8 +1160,8 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
839
1160
|
}
|
|
840
1161
|
calls.push({
|
|
841
1162
|
target: VENICE().VVV,
|
|
842
|
-
data:
|
|
843
|
-
abi:
|
|
1163
|
+
data: encodeFunctionData5({
|
|
1164
|
+
abi: ERC20_ABI2,
|
|
844
1165
|
functionName: "approve",
|
|
845
1166
|
args: [VENICE().STAKING, minVVV]
|
|
846
1167
|
}),
|
|
@@ -850,7 +1171,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
850
1171
|
for (const agent of agents) {
|
|
851
1172
|
calls.push({
|
|
852
1173
|
target: VENICE().STAKING,
|
|
853
|
-
data:
|
|
1174
|
+
data: encodeFunctionData5({
|
|
854
1175
|
abi: STAKING_ABI,
|
|
855
1176
|
functionName: "stake",
|
|
856
1177
|
args: [agent, perAgent]
|
|
@@ -865,16 +1186,22 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
865
1186
|
var VENICE_API_BASE = "https://api.venice.ai/api/v1";
|
|
866
1187
|
async function provisionApiKey() {
|
|
867
1188
|
const account = getAccount();
|
|
868
|
-
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key
|
|
1189
|
+
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
1190
|
+
signal: AbortSignal.timeout(15e3)
|
|
1191
|
+
});
|
|
869
1192
|
if (!tokenRes.ok) {
|
|
870
1193
|
throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
|
|
871
1194
|
}
|
|
872
1195
|
const tokenData = await tokenRes.json();
|
|
873
|
-
const token = tokenData
|
|
1196
|
+
const token = tokenData?.data?.token;
|
|
1197
|
+
if (!token) {
|
|
1198
|
+
throw new Error("Venice API returned no validation token");
|
|
1199
|
+
}
|
|
874
1200
|
const signature = await account.signMessage({ message: token });
|
|
875
1201
|
const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
876
1202
|
method: "POST",
|
|
877
1203
|
headers: { "Content-Type": "application/json" },
|
|
1204
|
+
signal: AbortSignal.timeout(15e3),
|
|
878
1205
|
body: JSON.stringify({
|
|
879
1206
|
address: account.address,
|
|
880
1207
|
signature,
|
|
@@ -888,28 +1215,92 @@ async function provisionApiKey() {
|
|
|
888
1215
|
throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
|
|
889
1216
|
}
|
|
890
1217
|
const keyData = await keyRes.json();
|
|
891
|
-
const apiKey = keyData
|
|
1218
|
+
const apiKey = keyData?.data?.apiKey;
|
|
1219
|
+
if (!apiKey) {
|
|
1220
|
+
throw new Error("Venice API returned no API key");
|
|
1221
|
+
}
|
|
892
1222
|
setVeniceApiKey(apiKey);
|
|
893
1223
|
return apiKey;
|
|
894
1224
|
}
|
|
895
|
-
async function checkApiKeyValid() {
|
|
1225
|
+
async function checkApiKeyValid() {
|
|
1226
|
+
const apiKey = getVeniceApiKey();
|
|
1227
|
+
if (!apiKey) return false;
|
|
1228
|
+
try {
|
|
1229
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
1230
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1231
|
+
signal: AbortSignal.timeout(15e3)
|
|
1232
|
+
});
|
|
1233
|
+
return res.ok;
|
|
1234
|
+
} catch {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
async function chatCompletion(opts) {
|
|
1239
|
+
const apiKey = getVeniceApiKey();
|
|
1240
|
+
if (!apiKey) {
|
|
1241
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
1242
|
+
}
|
|
1243
|
+
const body = {
|
|
1244
|
+
model: opts.model,
|
|
1245
|
+
messages: opts.messages
|
|
1246
|
+
};
|
|
1247
|
+
if (opts.temperature !== void 0) body.temperature = opts.temperature;
|
|
1248
|
+
if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
|
|
1249
|
+
const veniceParams = {};
|
|
1250
|
+
if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
|
|
1251
|
+
if (opts.disableThinking) veniceParams.disable_thinking = true;
|
|
1252
|
+
if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
|
|
1253
|
+
const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
|
|
1254
|
+
method: "POST",
|
|
1255
|
+
headers: {
|
|
1256
|
+
"Content-Type": "application/json",
|
|
1257
|
+
Authorization: `Bearer ${apiKey}`
|
|
1258
|
+
},
|
|
1259
|
+
signal: AbortSignal.timeout(12e4),
|
|
1260
|
+
// inference can be slow
|
|
1261
|
+
body: JSON.stringify(body)
|
|
1262
|
+
});
|
|
1263
|
+
if (!res.ok) {
|
|
1264
|
+
const errBody = await res.text();
|
|
1265
|
+
throw new Error(`Venice inference failed: ${res.status} ${errBody}`);
|
|
1266
|
+
}
|
|
1267
|
+
const data = await res.json();
|
|
1268
|
+
const choice = data.choices?.[0];
|
|
1269
|
+
if (!choice) {
|
|
1270
|
+
throw new Error("Venice returned no choices");
|
|
1271
|
+
}
|
|
1272
|
+
return {
|
|
1273
|
+
content: choice.message?.content ?? "",
|
|
1274
|
+
model: data.model ?? opts.model,
|
|
1275
|
+
usage: {
|
|
1276
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
1277
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
1278
|
+
totalTokens: data.usage?.total_tokens ?? 0
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
async function listModels() {
|
|
896
1283
|
const apiKey = getVeniceApiKey();
|
|
897
|
-
if (!apiKey)
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
|
|
1284
|
+
if (!apiKey) {
|
|
1285
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
1286
|
+
}
|
|
1287
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
1288
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1289
|
+
signal: AbortSignal.timeout(15e3)
|
|
1290
|
+
});
|
|
1291
|
+
if (!res.ok) {
|
|
1292
|
+
throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
|
|
905
1293
|
}
|
|
1294
|
+
const data = await res.json();
|
|
1295
|
+
return (data.data ?? []).map((m) => m.id);
|
|
906
1296
|
}
|
|
907
1297
|
|
|
908
1298
|
// src/commands/venice.ts
|
|
909
|
-
|
|
1299
|
+
import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1300
|
+
var VALID_FEES = [500, 3e3, 1e4];
|
|
910
1301
|
function registerVeniceCommands(program2) {
|
|
911
1302
|
const venice = program2.command("venice").description("Venice private inference \u2014 stake VVV, provision API keys");
|
|
912
|
-
venice.command("fund").description("Swap vault profits \u2192 VVV \u2192 stake \u2192 distribute sVVV to agents").requiredOption("--vault <address>", "Vault address").requiredOption("--amount <amount>", "Deposit token amount to convert (e.g. 500)").option("--fee1 <tier>", "Fee tier for asset \u2192 WETH hop (500, 3000, 10000)", "3000").option("--fee2 <tier>", "Fee tier for WETH \u2192 VVV hop", "10000").option("--slippage <bps>", "Slippage tolerance in bps", "100").option("--execute", "Execute on-chain (default: simulate only)", false).action(async (opts) => {
|
|
1303
|
+
venice.command("fund").description("Swap vault profits \u2192 VVV \u2192 stake \u2192 distribute sVVV to agents").requiredOption("--vault <address>", "Vault address").requiredOption("--amount <amount>", "Deposit token amount to convert (e.g. 500)").option("--fee1 <tier>", "Fee tier for asset \u2192 WETH hop (500, 3000, 10000)", "3000").option("--fee2 <tier>", "Fee tier for WETH \u2192 VVV hop", "10000").option("--slippage <bps>", "Slippage tolerance in bps", "100").option("--execute", "Execute on-chain (default: simulate only)", false).option("--write-calls <path>", "Write batch calls to JSON file for proposal create (skips execution)").action(async (opts) => {
|
|
913
1304
|
const vaultAddress = opts.vault;
|
|
914
1305
|
if (!isAddress2(vaultAddress)) {
|
|
915
1306
|
console.error(chalk2.red(`Invalid vault address: ${opts.vault}`));
|
|
@@ -917,8 +1308,8 @@ function registerVeniceCommands(program2) {
|
|
|
917
1308
|
}
|
|
918
1309
|
const fee1 = Number(opts.fee1);
|
|
919
1310
|
const fee2 = Number(opts.fee2);
|
|
920
|
-
if (!
|
|
921
|
-
console.error(chalk2.red(`Invalid fee tier. Valid: ${
|
|
1311
|
+
if (!VALID_FEES.includes(fee1) || !VALID_FEES.includes(fee2)) {
|
|
1312
|
+
console.error(chalk2.red(`Invalid fee tier. Valid: ${VALID_FEES.join(", ")}`));
|
|
922
1313
|
process.exit(1);
|
|
923
1314
|
}
|
|
924
1315
|
const slippageBps = Number(opts.slippage);
|
|
@@ -951,7 +1342,7 @@ function registerVeniceCommands(program2) {
|
|
|
951
1342
|
console.error(chalk2.red("No agents registered in vault. Register agents first."));
|
|
952
1343
|
process.exit(1);
|
|
953
1344
|
}
|
|
954
|
-
const requestedAmount =
|
|
1345
|
+
const requestedAmount = parseUnits4(opts.amount, assetDecimals);
|
|
955
1346
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
956
1347
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
957
1348
|
console.log();
|
|
@@ -959,16 +1350,16 @@ function registerVeniceCommands(program2) {
|
|
|
959
1350
|
console.log(chalk2.dim("\u2500".repeat(40)));
|
|
960
1351
|
console.log(` Asset: ${assetSymbol} (${assetDecimals} decimals)`);
|
|
961
1352
|
console.log(` Amount: ${opts.amount} ${assetSymbol}`);
|
|
962
|
-
console.log(` Vault balance: ${
|
|
963
|
-
console.log(` Deposited: ${
|
|
964
|
-
console.log(` Profit: ${
|
|
1353
|
+
console.log(` Vault balance: ${formatUnits2(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
1354
|
+
console.log(` Deposited: ${formatUnits2(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
1355
|
+
console.log(` Profit: ${formatUnits2(profit, assetDecimals)} ${assetSymbol}`);
|
|
965
1356
|
console.log(` Agents: ${agents.length} (sVVV will be split equally)`);
|
|
966
1357
|
console.log(` Routing: ${isWeth ? `WETH \u2192 VVV (fee ${fee2})` : `${assetSymbol} \u2192 WETH (fee ${fee1}) \u2192 VVV (fee ${fee2})`}`);
|
|
967
1358
|
console.log(` Slippage: ${(slippageBps / 100).toFixed(2)}%`);
|
|
968
1359
|
console.log(` Vault: ${vaultAddress}`);
|
|
969
1360
|
console.log();
|
|
970
1361
|
if (requestedAmount > profit) {
|
|
971
|
-
console.warn(chalk2.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${
|
|
1362
|
+
console.warn(chalk2.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits2(profit, assetDecimals)})`));
|
|
972
1363
|
console.warn(chalk2.yellow(" This will use deposited capital, not just profits."));
|
|
973
1364
|
console.log();
|
|
974
1365
|
}
|
|
@@ -998,7 +1389,7 @@ function registerVeniceCommands(program2) {
|
|
|
998
1389
|
}
|
|
999
1390
|
minOut = applySlippage(amountOut, slippageBps);
|
|
1000
1391
|
quoteSpinner.succeed(
|
|
1001
|
-
`Quote: ${
|
|
1392
|
+
`Quote: ${formatUnits2(amountOut, 18)} VVV (min: ${formatUnits2(minOut, 18)}, per agent: ${formatUnits2(minOut / BigInt(agents.length), 18)})`
|
|
1002
1393
|
);
|
|
1003
1394
|
} catch (err) {
|
|
1004
1395
|
quoteSpinner.fail("Failed to fetch quote");
|
|
@@ -1016,9 +1407,24 @@ function registerVeniceCommands(program2) {
|
|
|
1016
1407
|
console.log(chalk2.bold(`Batch calls (${calls.length}):`));
|
|
1017
1408
|
console.log(formatBatch(calls));
|
|
1018
1409
|
console.log();
|
|
1410
|
+
if (opts.writeCalls) {
|
|
1411
|
+
const callsJson = calls.map((c) => ({
|
|
1412
|
+
target: c.target,
|
|
1413
|
+
data: c.data,
|
|
1414
|
+
value: c.value.toString()
|
|
1415
|
+
}));
|
|
1416
|
+
writeFileSync2(opts.writeCalls, JSON.stringify(callsJson, null, 2));
|
|
1417
|
+
const settlePath = `${opts.writeCalls}.settle.json`;
|
|
1418
|
+
writeFileSync2(settlePath, "[]");
|
|
1419
|
+
console.log(chalk2.green(`Execute calls written to: ${opts.writeCalls}`));
|
|
1420
|
+
console.log(chalk2.green(`Settlement calls written to: ${settlePath}`));
|
|
1421
|
+
console.log();
|
|
1422
|
+
console.log(chalk2.dim("Use with: sherwood proposal create --execute-calls <path> --settle-calls <path>"));
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1019
1425
|
if (!opts.execute) {
|
|
1020
1426
|
console.log();
|
|
1021
|
-
console.log(chalk2.yellow("Dry run complete. Add --execute to submit on-chain."));
|
|
1427
|
+
console.log(chalk2.yellow("Dry run complete. Add --execute to submit on-chain, or --write-calls <path> to export for proposals."));
|
|
1022
1428
|
return;
|
|
1023
1429
|
}
|
|
1024
1430
|
const execSpinner = ora2("Executing batch via vault...").start();
|
|
@@ -1049,7 +1455,7 @@ function registerVeniceCommands(program2) {
|
|
|
1049
1455
|
console.log(chalk2.yellow(" Run 'sherwood venice fund' first to distribute sVVV to agents."));
|
|
1050
1456
|
process.exit(1);
|
|
1051
1457
|
}
|
|
1052
|
-
checkSpinner.succeed(`sVVV balance: ${
|
|
1458
|
+
checkSpinner.succeed(`sVVV balance: ${formatUnits2(sVvvBalance, 18)}`);
|
|
1053
1459
|
} catch (err) {
|
|
1054
1460
|
checkSpinner.fail("Failed to check sVVV balance");
|
|
1055
1461
|
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
@@ -1126,17 +1532,17 @@ function registerVeniceCommands(program2) {
|
|
|
1126
1532
|
console.log(chalk2.bold("Venice Inference Status"));
|
|
1127
1533
|
console.log(chalk2.dim("\u2500".repeat(50)));
|
|
1128
1534
|
console.log(chalk2.bold("\n Vault"));
|
|
1129
|
-
console.log(` Profit available: ${
|
|
1130
|
-
console.log(` VVV (unstaked): ${
|
|
1535
|
+
console.log(` Profit available: ${formatUnits2(profit, assetDecimals)} ${assetSymbol}`);
|
|
1536
|
+
console.log(` VVV (unstaked): ${formatUnits2(vaultVvvBalance, 18)}`);
|
|
1131
1537
|
console.log(chalk2.bold("\n Agent sVVV Balances"));
|
|
1132
1538
|
for (const { agent, balance } of agentBalances) {
|
|
1133
1539
|
const isMe = agent.toLowerCase() === account.address.toLowerCase();
|
|
1134
1540
|
const label = isMe ? chalk2.green(`${agent} (you)`) : agent;
|
|
1135
|
-
console.log(` ${label}: ${
|
|
1541
|
+
console.log(` ${label}: ${formatUnits2(balance, 18)} sVVV`);
|
|
1136
1542
|
}
|
|
1137
1543
|
console.log(chalk2.bold("\n Your Wallet"));
|
|
1138
|
-
console.log(` sVVV: ${
|
|
1139
|
-
console.log(` Pending rewards: ${
|
|
1544
|
+
console.log(` sVVV: ${formatUnits2(mySvvv, 18)}`);
|
|
1545
|
+
console.log(` Pending rewards: ${formatUnits2(myPending, 18)} VVV`);
|
|
1140
1546
|
console.log(chalk2.bold("\n Venice API"));
|
|
1141
1547
|
console.log(` Key: ${apiKey ? `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}` : chalk2.dim("not provisioned")}`);
|
|
1142
1548
|
console.log(` Status: ${apiKeyValid ? chalk2.green("valid") : chalk2.red("invalid/missing")}`);
|
|
@@ -1147,16 +1553,79 @@ function registerVeniceCommands(program2) {
|
|
|
1147
1553
|
process.exit(1);
|
|
1148
1554
|
}
|
|
1149
1555
|
});
|
|
1556
|
+
venice.command("models").description("List available Venice inference models").action(async () => {
|
|
1557
|
+
const spinner = ora2("Fetching Venice models...").start();
|
|
1558
|
+
try {
|
|
1559
|
+
const models = await listModels();
|
|
1560
|
+
spinner.succeed(`${models.length} models available`);
|
|
1561
|
+
console.log();
|
|
1562
|
+
for (const model of models) {
|
|
1563
|
+
console.log(` ${model}`);
|
|
1564
|
+
}
|
|
1565
|
+
console.log();
|
|
1566
|
+
} catch (err) {
|
|
1567
|
+
spinner.fail("Failed to list models");
|
|
1568
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1569
|
+
process.exit(1);
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
venice.command("infer").description("Run private inference via Venice chat completions").requiredOption("--prompt <text>", "User prompt").requiredOption("--model <id>", "Venice model ID (use 'venice models' to list)").option("--system <text>", "System prompt").option("--data <path>", "Path to data file \u2014 contents prepended to prompt as context").option("--web-search", "Enable Venice web search", false).option("--no-thinking", "Disable chain-of-thought reasoning").option("--temperature <n>", "Sampling temperature (0-2)").option("--max-tokens <n>", "Maximum completion tokens").option("--json", "Output raw JSON response", false).action(async (opts) => {
|
|
1573
|
+
const messages = [];
|
|
1574
|
+
if (opts.system) {
|
|
1575
|
+
messages.push({ role: "system", content: opts.system });
|
|
1576
|
+
}
|
|
1577
|
+
let userContent = opts.prompt;
|
|
1578
|
+
if (opts.data) {
|
|
1579
|
+
try {
|
|
1580
|
+
const data = readFileSync(opts.data, "utf-8");
|
|
1581
|
+
userContent = `Context data:
|
|
1582
|
+
\`\`\`
|
|
1583
|
+
${data}
|
|
1584
|
+
\`\`\`
|
|
1585
|
+
|
|
1586
|
+
${opts.prompt}`;
|
|
1587
|
+
} catch (err) {
|
|
1588
|
+
console.error(chalk2.red(`Failed to read data file: ${opts.data}`));
|
|
1589
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1590
|
+
process.exit(1);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
messages.push({ role: "user", content: userContent });
|
|
1594
|
+
const spinner = ora2(`Running inference (${opts.model})...`).start();
|
|
1595
|
+
try {
|
|
1596
|
+
const result = await chatCompletion({
|
|
1597
|
+
model: opts.model,
|
|
1598
|
+
messages,
|
|
1599
|
+
temperature: opts.temperature !== void 0 ? Number(opts.temperature) : void 0,
|
|
1600
|
+
maxTokens: opts.maxTokens !== void 0 ? Number(opts.maxTokens) : void 0,
|
|
1601
|
+
enableWebSearch: opts.webSearch,
|
|
1602
|
+
disableThinking: opts.thinking === false
|
|
1603
|
+
});
|
|
1604
|
+
spinner.succeed("Inference complete");
|
|
1605
|
+
if (opts.json) {
|
|
1606
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1607
|
+
} else {
|
|
1608
|
+
console.log();
|
|
1609
|
+
console.log(result.content);
|
|
1610
|
+
console.log();
|
|
1611
|
+
console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
|
|
1612
|
+
}
|
|
1613
|
+
} catch (err) {
|
|
1614
|
+
spinner.fail("Inference failed");
|
|
1615
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1616
|
+
process.exit(1);
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1150
1619
|
}
|
|
1151
1620
|
|
|
1152
1621
|
// src/commands/allowance.ts
|
|
1153
|
-
import { parseUnits as
|
|
1622
|
+
import { parseUnits as parseUnits6, formatUnits as formatUnits3, isAddress as isAddress3 } from "viem";
|
|
1154
1623
|
import chalk3 from "chalk";
|
|
1155
1624
|
import ora3 from "ora";
|
|
1156
1625
|
|
|
1157
1626
|
// src/strategies/allowance-disburse.ts
|
|
1158
|
-
import { encodeFunctionData as
|
|
1159
|
-
var
|
|
1627
|
+
import { encodeFunctionData as encodeFunctionData6, parseUnits as parseUnits5 } from "viem";
|
|
1628
|
+
var ERC20_ABI3 = [
|
|
1160
1629
|
{
|
|
1161
1630
|
name: "approve",
|
|
1162
1631
|
type: "function",
|
|
@@ -1218,15 +1687,15 @@ var SWAP_ROUTER_EXACT_INPUT_ABI2 = [
|
|
|
1218
1687
|
}
|
|
1219
1688
|
];
|
|
1220
1689
|
function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minUsdc, swapPath) {
|
|
1221
|
-
const assetAmount =
|
|
1690
|
+
const assetAmount = parseUnits5(config.amount, assetDecimals);
|
|
1222
1691
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
1223
1692
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
1224
1693
|
const calls = [];
|
|
1225
1694
|
if (!isUsdc) {
|
|
1226
1695
|
calls.push({
|
|
1227
1696
|
target: assetAddress,
|
|
1228
|
-
data:
|
|
1229
|
-
abi:
|
|
1697
|
+
data: encodeFunctionData6({
|
|
1698
|
+
abi: ERC20_ABI3,
|
|
1230
1699
|
functionName: "approve",
|
|
1231
1700
|
args: [UNISWAP().SWAP_ROUTER, assetAmount]
|
|
1232
1701
|
}),
|
|
@@ -1235,7 +1704,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1235
1704
|
if (isWeth) {
|
|
1236
1705
|
calls.push({
|
|
1237
1706
|
target: UNISWAP().SWAP_ROUTER,
|
|
1238
|
-
data:
|
|
1707
|
+
data: encodeFunctionData6({
|
|
1239
1708
|
abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI2,
|
|
1240
1709
|
functionName: "exactInputSingle",
|
|
1241
1710
|
args: [
|
|
@@ -1255,7 +1724,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1255
1724
|
} else {
|
|
1256
1725
|
calls.push({
|
|
1257
1726
|
target: UNISWAP().SWAP_ROUTER,
|
|
1258
|
-
data:
|
|
1727
|
+
data: encodeFunctionData6({
|
|
1259
1728
|
abi: SWAP_ROUTER_EXACT_INPUT_ABI2,
|
|
1260
1729
|
functionName: "exactInput",
|
|
1261
1730
|
args: [
|
|
@@ -1275,8 +1744,8 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1275
1744
|
for (const agent of agents) {
|
|
1276
1745
|
calls.push({
|
|
1277
1746
|
target: TOKENS().USDC,
|
|
1278
|
-
data:
|
|
1279
|
-
abi:
|
|
1747
|
+
data: encodeFunctionData6({
|
|
1748
|
+
abi: ERC20_ABI3,
|
|
1280
1749
|
functionName: "transfer",
|
|
1281
1750
|
args: [agent, perAgent]
|
|
1282
1751
|
}),
|
|
@@ -1287,7 +1756,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1287
1756
|
}
|
|
1288
1757
|
|
|
1289
1758
|
// src/commands/allowance.ts
|
|
1290
|
-
var
|
|
1759
|
+
var VALID_FEES2 = [500, 3e3, 1e4];
|
|
1291
1760
|
function registerAllowanceCommands(program2) {
|
|
1292
1761
|
const allowance = program2.command("allowance").description("Disburse vault profits to agent wallets");
|
|
1293
1762
|
allowance.command("disburse").description("Swap vault profits \u2192 USDC \u2192 distribute to all agent operator wallets").requiredOption("--vault <address>", "Vault address").requiredOption("--amount <amount>", "Deposit token amount to convert & distribute (e.g. 500)").option("--fee <tier>", "Fee tier for asset \u2192 USDC swap (500, 3000, 10000)", "3000").option("--slippage <bps>", "Slippage tolerance in bps", "100").option("--execute", "Execute on-chain (default: simulate only)", false).action(async (opts) => {
|
|
@@ -1297,8 +1766,8 @@ function registerAllowanceCommands(program2) {
|
|
|
1297
1766
|
process.exit(1);
|
|
1298
1767
|
}
|
|
1299
1768
|
const fee = Number(opts.fee);
|
|
1300
|
-
if (!
|
|
1301
|
-
console.error(chalk3.red(`Invalid fee tier. Valid: ${
|
|
1769
|
+
if (!VALID_FEES2.includes(fee)) {
|
|
1770
|
+
console.error(chalk3.red(`Invalid fee tier. Valid: ${VALID_FEES2.join(", ")}`));
|
|
1302
1771
|
process.exit(1);
|
|
1303
1772
|
}
|
|
1304
1773
|
const slippageBps = Number(opts.slippage);
|
|
@@ -1331,7 +1800,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1331
1800
|
console.error(chalk3.red("No agents registered in vault. Register agents first."));
|
|
1332
1801
|
process.exit(1);
|
|
1333
1802
|
}
|
|
1334
|
-
const requestedAmount =
|
|
1803
|
+
const requestedAmount = parseUnits6(opts.amount, assetDecimals);
|
|
1335
1804
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
1336
1805
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
1337
1806
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
@@ -1340,9 +1809,9 @@ function registerAllowanceCommands(program2) {
|
|
|
1340
1809
|
console.log(chalk3.dim("\u2500".repeat(40)));
|
|
1341
1810
|
console.log(` Asset: ${assetSymbol} (${assetDecimals} decimals)`);
|
|
1342
1811
|
console.log(` Amount: ${opts.amount} ${assetSymbol}`);
|
|
1343
|
-
console.log(` Vault balance: ${
|
|
1344
|
-
console.log(` Deposited: ${
|
|
1345
|
-
console.log(` Profit: ${
|
|
1812
|
+
console.log(` Vault balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
1813
|
+
console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
1814
|
+
console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
|
|
1346
1815
|
console.log(` Agents: ${agents.length} (USDC will be split equally)`);
|
|
1347
1816
|
if (!isUsdc) {
|
|
1348
1817
|
console.log(` Routing: ${isWeth ? `WETH \u2192 USDC (fee ${fee})` : `${assetSymbol} \u2192 WETH \u2192 USDC (fee ${fee})`}`);
|
|
@@ -1351,7 +1820,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1351
1820
|
console.log(` Vault: ${vaultAddress}`);
|
|
1352
1821
|
console.log();
|
|
1353
1822
|
if (requestedAmount > profit) {
|
|
1354
|
-
console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${
|
|
1823
|
+
console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits3(profit, assetDecimals)})`));
|
|
1355
1824
|
console.warn(chalk3.yellow(" This will use deposited capital, not just profits."));
|
|
1356
1825
|
console.log();
|
|
1357
1826
|
}
|
|
@@ -1385,7 +1854,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1385
1854
|
}
|
|
1386
1855
|
minUsdc = applySlippage(amountOut, slippageBps);
|
|
1387
1856
|
quoteSpinner.succeed(
|
|
1388
|
-
`Quote: ${
|
|
1857
|
+
`Quote: ${formatUnits3(amountOut, 6)} USDC (min: ${formatUnits3(minUsdc, 6)}, per agent: ${formatUnits3(minUsdc / BigInt(agents.length), 6)})`
|
|
1389
1858
|
);
|
|
1390
1859
|
} catch (err) {
|
|
1391
1860
|
quoteSpinner.fail("Failed to fetch quote");
|
|
@@ -1395,7 +1864,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1395
1864
|
}
|
|
1396
1865
|
const perAgent = minUsdc / BigInt(agents.length);
|
|
1397
1866
|
if (isUsdc) {
|
|
1398
|
-
console.log(chalk3.dim(` Per agent: ${
|
|
1867
|
+
console.log(chalk3.dim(` Per agent: ${formatUnits3(perAgent, 6)} USDC`));
|
|
1399
1868
|
console.log();
|
|
1400
1869
|
}
|
|
1401
1870
|
const config = {
|
|
@@ -1462,14 +1931,14 @@ function registerAllowanceCommands(program2) {
|
|
|
1462
1931
|
console.log(chalk3.dim("\u2500".repeat(50)));
|
|
1463
1932
|
console.log(chalk3.bold("\n Vault"));
|
|
1464
1933
|
console.log(` Asset: ${assetSymbol}`);
|
|
1465
|
-
console.log(` Balance: ${
|
|
1466
|
-
console.log(` Deposited: ${
|
|
1467
|
-
console.log(` Profit: ${
|
|
1934
|
+
console.log(` Balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
1935
|
+
console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
1936
|
+
console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
|
|
1468
1937
|
console.log(chalk3.bold("\n Agent USDC Balances"));
|
|
1469
1938
|
for (const { agent, balance } of agentBalances) {
|
|
1470
1939
|
const isMe = agent.toLowerCase() === account.address.toLowerCase();
|
|
1471
1940
|
const label = isMe ? chalk3.green(`${agent} (you)`) : agent;
|
|
1472
|
-
console.log(` ${label}: ${
|
|
1941
|
+
console.log(` ${label}: ${formatUnits3(balance, 6)} USDC`);
|
|
1473
1942
|
}
|
|
1474
1943
|
console.log();
|
|
1475
1944
|
} catch (err) {
|
|
@@ -1641,348 +2110,7 @@ function registerIdentityCommands(program2) {
|
|
|
1641
2110
|
import { isAddress as isAddress4 } from "viem";
|
|
1642
2111
|
import chalk5 from "chalk";
|
|
1643
2112
|
import ora5 from "ora";
|
|
1644
|
-
import { readFileSync } from "fs";
|
|
1645
|
-
|
|
1646
|
-
// src/lib/governor.ts
|
|
1647
|
-
var PROPOSAL_STATES = [
|
|
1648
|
-
"Draft",
|
|
1649
|
-
"Pending",
|
|
1650
|
-
"Approved",
|
|
1651
|
-
"Rejected",
|
|
1652
|
-
"Expired",
|
|
1653
|
-
"Executed",
|
|
1654
|
-
"Settled",
|
|
1655
|
-
"Cancelled"
|
|
1656
|
-
];
|
|
1657
|
-
var PROPOSAL_STATE = {
|
|
1658
|
-
Draft: 0,
|
|
1659
|
-
Pending: 1,
|
|
1660
|
-
Approved: 2,
|
|
1661
|
-
Rejected: 3,
|
|
1662
|
-
Expired: 4,
|
|
1663
|
-
Executed: 5,
|
|
1664
|
-
Settled: 6,
|
|
1665
|
-
Cancelled: 7
|
|
1666
|
-
};
|
|
1667
|
-
var VOTE_TYPE = {
|
|
1668
|
-
For: 0,
|
|
1669
|
-
Against: 1,
|
|
1670
|
-
Abstain: 2
|
|
1671
|
-
};
|
|
1672
|
-
function parseDuration(input2) {
|
|
1673
|
-
const match = input2.match(/^(\d+)(d|h|m|s)?$/);
|
|
1674
|
-
if (!match) throw new Error(`Invalid duration: ${input2}`);
|
|
1675
|
-
const value = BigInt(match[1]);
|
|
1676
|
-
switch (match[2]) {
|
|
1677
|
-
case "d":
|
|
1678
|
-
return value * 86400n;
|
|
1679
|
-
case "h":
|
|
1680
|
-
return value * 3600n;
|
|
1681
|
-
case "m":
|
|
1682
|
-
return value * 60n;
|
|
1683
|
-
case "s":
|
|
1684
|
-
case void 0:
|
|
1685
|
-
return value;
|
|
1686
|
-
default:
|
|
1687
|
-
throw new Error(`Unknown duration unit: ${match[2]}`);
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
function getGovernorAddress() {
|
|
1691
|
-
return SHERWOOD().GOVERNOR;
|
|
1692
|
-
}
|
|
1693
|
-
async function getGovernorParams() {
|
|
1694
|
-
const client = getPublicClient();
|
|
1695
|
-
const result = await client.readContract({
|
|
1696
|
-
address: getGovernorAddress(),
|
|
1697
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1698
|
-
functionName: "getGovernorParams"
|
|
1699
|
-
});
|
|
1700
|
-
return result;
|
|
1701
|
-
}
|
|
1702
|
-
async function getProposal(id) {
|
|
1703
|
-
const client = getPublicClient();
|
|
1704
|
-
const result = await client.readContract({
|
|
1705
|
-
address: getGovernorAddress(),
|
|
1706
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1707
|
-
functionName: "getProposal",
|
|
1708
|
-
args: [id]
|
|
1709
|
-
});
|
|
1710
|
-
return result;
|
|
1711
|
-
}
|
|
1712
|
-
async function getProposalState(id) {
|
|
1713
|
-
const client = getPublicClient();
|
|
1714
|
-
return client.readContract({
|
|
1715
|
-
address: getGovernorAddress(),
|
|
1716
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1717
|
-
functionName: "getProposalState",
|
|
1718
|
-
args: [id]
|
|
1719
|
-
});
|
|
1720
|
-
}
|
|
1721
|
-
async function proposalCount() {
|
|
1722
|
-
const client = getPublicClient();
|
|
1723
|
-
return client.readContract({
|
|
1724
|
-
address: getGovernorAddress(),
|
|
1725
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1726
|
-
functionName: "proposalCount"
|
|
1727
|
-
});
|
|
1728
|
-
}
|
|
1729
|
-
async function getVoteWeight(proposalId, voter) {
|
|
1730
|
-
const client = getPublicClient();
|
|
1731
|
-
return client.readContract({
|
|
1732
|
-
address: getGovernorAddress(),
|
|
1733
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1734
|
-
functionName: "getVoteWeight",
|
|
1735
|
-
args: [proposalId, voter]
|
|
1736
|
-
});
|
|
1737
|
-
}
|
|
1738
|
-
async function hasVoted(proposalId, voter) {
|
|
1739
|
-
const client = getPublicClient();
|
|
1740
|
-
return client.readContract({
|
|
1741
|
-
address: getGovernorAddress(),
|
|
1742
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1743
|
-
functionName: "hasVoted",
|
|
1744
|
-
args: [proposalId, voter]
|
|
1745
|
-
});
|
|
1746
|
-
}
|
|
1747
|
-
async function getExecuteCalls(proposalId) {
|
|
1748
|
-
const client = getPublicClient();
|
|
1749
|
-
const result = await client.readContract({
|
|
1750
|
-
address: getGovernorAddress(),
|
|
1751
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1752
|
-
functionName: "getExecuteCalls",
|
|
1753
|
-
args: [proposalId]
|
|
1754
|
-
});
|
|
1755
|
-
return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));
|
|
1756
|
-
}
|
|
1757
|
-
async function getSettlementCalls(proposalId) {
|
|
1758
|
-
const client = getPublicClient();
|
|
1759
|
-
const result = await client.readContract({
|
|
1760
|
-
address: getGovernorAddress(),
|
|
1761
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1762
|
-
functionName: "getSettlementCalls",
|
|
1763
|
-
args: [proposalId]
|
|
1764
|
-
});
|
|
1765
|
-
return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));
|
|
1766
|
-
}
|
|
1767
|
-
async function getRegisteredVaults() {
|
|
1768
|
-
const client = getPublicClient();
|
|
1769
|
-
return client.readContract({
|
|
1770
|
-
address: getGovernorAddress(),
|
|
1771
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1772
|
-
functionName: "getRegisteredVaults"
|
|
1773
|
-
});
|
|
1774
|
-
}
|
|
1775
|
-
async function getCapitalSnapshot(proposalId) {
|
|
1776
|
-
const client = getPublicClient();
|
|
1777
|
-
return client.readContract({
|
|
1778
|
-
address: getGovernorAddress(),
|
|
1779
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1780
|
-
functionName: "getCapitalSnapshot",
|
|
1781
|
-
args: [proposalId]
|
|
1782
|
-
});
|
|
1783
|
-
}
|
|
1784
|
-
async function propose(vault, metadataURI, performanceFeeBps, strategyDuration, executeCalls, settlementCalls, coProposers = []) {
|
|
1785
|
-
const wallet = getWalletClient();
|
|
1786
|
-
const client = getPublicClient();
|
|
1787
|
-
const hash = await wallet.writeContract({
|
|
1788
|
-
account: getAccount(),
|
|
1789
|
-
chain: getChain(),
|
|
1790
|
-
address: getGovernorAddress(),
|
|
1791
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1792
|
-
functionName: "propose",
|
|
1793
|
-
args: [vault, metadataURI, performanceFeeBps, strategyDuration, executeCalls, settlementCalls, coProposers]
|
|
1794
|
-
});
|
|
1795
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1796
|
-
let proposalId;
|
|
1797
|
-
try {
|
|
1798
|
-
proposalId = await proposalCount();
|
|
1799
|
-
} catch {
|
|
1800
|
-
proposalId = 0n;
|
|
1801
|
-
}
|
|
1802
|
-
return { hash: receipt.transactionHash, proposalId };
|
|
1803
|
-
}
|
|
1804
|
-
async function vote(proposalId, support) {
|
|
1805
|
-
const wallet = getWalletClient();
|
|
1806
|
-
const client = getPublicClient();
|
|
1807
|
-
const hash = await wallet.writeContract({
|
|
1808
|
-
account: getAccount(),
|
|
1809
|
-
chain: getChain(),
|
|
1810
|
-
address: getGovernorAddress(),
|
|
1811
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1812
|
-
functionName: "vote",
|
|
1813
|
-
args: [proposalId, support]
|
|
1814
|
-
});
|
|
1815
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1816
|
-
return receipt.transactionHash;
|
|
1817
|
-
}
|
|
1818
|
-
async function executeProposal(proposalId) {
|
|
1819
|
-
const wallet = getWalletClient();
|
|
1820
|
-
const client = getPublicClient();
|
|
1821
|
-
const hash = await wallet.writeContract({
|
|
1822
|
-
account: getAccount(),
|
|
1823
|
-
chain: getChain(),
|
|
1824
|
-
address: getGovernorAddress(),
|
|
1825
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1826
|
-
functionName: "executeProposal",
|
|
1827
|
-
args: [proposalId]
|
|
1828
|
-
});
|
|
1829
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1830
|
-
return receipt.transactionHash;
|
|
1831
|
-
}
|
|
1832
|
-
async function settleProposal(proposalId) {
|
|
1833
|
-
const wallet = getWalletClient();
|
|
1834
|
-
const client = getPublicClient();
|
|
1835
|
-
const hash = await wallet.writeContract({
|
|
1836
|
-
account: getAccount(),
|
|
1837
|
-
chain: getChain(),
|
|
1838
|
-
address: getGovernorAddress(),
|
|
1839
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1840
|
-
functionName: "settleProposal",
|
|
1841
|
-
args: [proposalId]
|
|
1842
|
-
});
|
|
1843
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1844
|
-
return receipt.transactionHash;
|
|
1845
|
-
}
|
|
1846
|
-
async function emergencySettle(proposalId, calls) {
|
|
1847
|
-
const wallet = getWalletClient();
|
|
1848
|
-
const client = getPublicClient();
|
|
1849
|
-
const hash = await wallet.writeContract({
|
|
1850
|
-
account: getAccount(),
|
|
1851
|
-
chain: getChain(),
|
|
1852
|
-
address: getGovernorAddress(),
|
|
1853
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1854
|
-
functionName: "emergencySettle",
|
|
1855
|
-
args: [proposalId, calls]
|
|
1856
|
-
});
|
|
1857
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1858
|
-
return receipt.transactionHash;
|
|
1859
|
-
}
|
|
1860
|
-
async function cancelProposal(proposalId) {
|
|
1861
|
-
const wallet = getWalletClient();
|
|
1862
|
-
const client = getPublicClient();
|
|
1863
|
-
const hash = await wallet.writeContract({
|
|
1864
|
-
account: getAccount(),
|
|
1865
|
-
chain: getChain(),
|
|
1866
|
-
address: getGovernorAddress(),
|
|
1867
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1868
|
-
functionName: "cancelProposal",
|
|
1869
|
-
args: [proposalId]
|
|
1870
|
-
});
|
|
1871
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1872
|
-
return receipt.transactionHash;
|
|
1873
|
-
}
|
|
1874
|
-
async function emergencyCancel(proposalId) {
|
|
1875
|
-
const wallet = getWalletClient();
|
|
1876
|
-
const client = getPublicClient();
|
|
1877
|
-
const hash = await wallet.writeContract({
|
|
1878
|
-
account: getAccount(),
|
|
1879
|
-
chain: getChain(),
|
|
1880
|
-
address: getGovernorAddress(),
|
|
1881
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1882
|
-
functionName: "emergencyCancel",
|
|
1883
|
-
args: [proposalId]
|
|
1884
|
-
});
|
|
1885
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1886
|
-
return receipt.transactionHash;
|
|
1887
|
-
}
|
|
1888
|
-
async function setVotingPeriod(seconds) {
|
|
1889
|
-
const wallet = getWalletClient();
|
|
1890
|
-
const client = getPublicClient();
|
|
1891
|
-
const hash = await wallet.writeContract({
|
|
1892
|
-
account: getAccount(),
|
|
1893
|
-
chain: getChain(),
|
|
1894
|
-
address: getGovernorAddress(),
|
|
1895
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1896
|
-
functionName: "setVotingPeriod",
|
|
1897
|
-
args: [seconds]
|
|
1898
|
-
});
|
|
1899
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1900
|
-
return receipt.transactionHash;
|
|
1901
|
-
}
|
|
1902
|
-
async function setExecutionWindow(seconds) {
|
|
1903
|
-
const wallet = getWalletClient();
|
|
1904
|
-
const client = getPublicClient();
|
|
1905
|
-
const hash = await wallet.writeContract({
|
|
1906
|
-
account: getAccount(),
|
|
1907
|
-
chain: getChain(),
|
|
1908
|
-
address: getGovernorAddress(),
|
|
1909
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1910
|
-
functionName: "setExecutionWindow",
|
|
1911
|
-
args: [seconds]
|
|
1912
|
-
});
|
|
1913
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1914
|
-
return receipt.transactionHash;
|
|
1915
|
-
}
|
|
1916
|
-
async function setVetoThresholdBps(bps) {
|
|
1917
|
-
const wallet = getWalletClient();
|
|
1918
|
-
const client = getPublicClient();
|
|
1919
|
-
const hash = await wallet.writeContract({
|
|
1920
|
-
account: getAccount(),
|
|
1921
|
-
chain: getChain(),
|
|
1922
|
-
address: getGovernorAddress(),
|
|
1923
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1924
|
-
functionName: "setVetoThresholdBps",
|
|
1925
|
-
args: [bps]
|
|
1926
|
-
});
|
|
1927
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1928
|
-
return receipt.transactionHash;
|
|
1929
|
-
}
|
|
1930
|
-
async function setMaxPerformanceFeeBps(bps) {
|
|
1931
|
-
const wallet = getWalletClient();
|
|
1932
|
-
const client = getPublicClient();
|
|
1933
|
-
const hash = await wallet.writeContract({
|
|
1934
|
-
account: getAccount(),
|
|
1935
|
-
chain: getChain(),
|
|
1936
|
-
address: getGovernorAddress(),
|
|
1937
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1938
|
-
functionName: "setMaxPerformanceFeeBps",
|
|
1939
|
-
args: [bps]
|
|
1940
|
-
});
|
|
1941
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1942
|
-
return receipt.transactionHash;
|
|
1943
|
-
}
|
|
1944
|
-
async function setMaxStrategyDuration(seconds) {
|
|
1945
|
-
const wallet = getWalletClient();
|
|
1946
|
-
const client = getPublicClient();
|
|
1947
|
-
const hash = await wallet.writeContract({
|
|
1948
|
-
account: getAccount(),
|
|
1949
|
-
chain: getChain(),
|
|
1950
|
-
address: getGovernorAddress(),
|
|
1951
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1952
|
-
functionName: "setMaxStrategyDuration",
|
|
1953
|
-
args: [seconds]
|
|
1954
|
-
});
|
|
1955
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1956
|
-
return receipt.transactionHash;
|
|
1957
|
-
}
|
|
1958
|
-
async function setCooldownPeriod(seconds) {
|
|
1959
|
-
const wallet = getWalletClient();
|
|
1960
|
-
const client = getPublicClient();
|
|
1961
|
-
const hash = await wallet.writeContract({
|
|
1962
|
-
account: getAccount(),
|
|
1963
|
-
chain: getChain(),
|
|
1964
|
-
address: getGovernorAddress(),
|
|
1965
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1966
|
-
functionName: "setCooldownPeriod",
|
|
1967
|
-
args: [seconds]
|
|
1968
|
-
});
|
|
1969
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1970
|
-
return receipt.transactionHash;
|
|
1971
|
-
}
|
|
1972
|
-
async function setProtocolFeeBps(bps) {
|
|
1973
|
-
const wallet = getWalletClient();
|
|
1974
|
-
const client = getPublicClient();
|
|
1975
|
-
const hash = await wallet.writeContract({
|
|
1976
|
-
account: getAccount(),
|
|
1977
|
-
chain: getChain(),
|
|
1978
|
-
address: getGovernorAddress(),
|
|
1979
|
-
abi: SYNDICATE_GOVERNOR_ABI,
|
|
1980
|
-
functionName: "setProtocolFeeBps",
|
|
1981
|
-
args: [bps]
|
|
1982
|
-
});
|
|
1983
|
-
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
1984
|
-
return receipt.transactionHash;
|
|
1985
|
-
}
|
|
2113
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1986
2114
|
|
|
1987
2115
|
// src/lib/format.ts
|
|
1988
2116
|
function formatDurationShort(seconds) {
|
|
@@ -2026,7 +2154,7 @@ function formatTimestamp(ts) {
|
|
|
2026
2154
|
return new Date(Number(ts) * 1e3).toLocaleString();
|
|
2027
2155
|
}
|
|
2028
2156
|
function parseCallsFile(path) {
|
|
2029
|
-
const raw =
|
|
2157
|
+
const raw = readFileSync2(path, "utf-8");
|
|
2030
2158
|
const parsed = JSON.parse(raw);
|
|
2031
2159
|
return parsed.map((c) => ({
|
|
2032
2160
|
target: c.target,
|
|
@@ -2512,7 +2640,7 @@ try {
|
|
|
2512
2640
|
var require2 = createRequire(import.meta.url);
|
|
2513
2641
|
var { version: CLI_VERSION } = require2("../package.json");
|
|
2514
2642
|
async function loadXmtp() {
|
|
2515
|
-
return import("./xmtp-
|
|
2643
|
+
return import("./xmtp-DX73F6I4.js");
|
|
2516
2644
|
}
|
|
2517
2645
|
async function loadCron() {
|
|
2518
2646
|
return import("./cron-SKYKVZ6K.js");
|
|
@@ -3189,7 +3317,7 @@ var vaultCmd = program.command("vault");
|
|
|
3189
3317
|
vaultCmd.command("deposit").description("Deposit into a vault").option("--vault <address>", "Vault address (default: from config)").requiredOption("--amount <amount>", "Amount to deposit (in asset units)").action(async (opts) => {
|
|
3190
3318
|
resolveVault(opts);
|
|
3191
3319
|
const decimals = await getAssetDecimals();
|
|
3192
|
-
const amount =
|
|
3320
|
+
const amount = parseUnits7(opts.amount, decimals);
|
|
3193
3321
|
const spinner = ora7(`Depositing ${opts.amount}...`).start();
|
|
3194
3322
|
try {
|
|
3195
3323
|
const hash = await deposit(amount);
|
|
@@ -3241,81 +3369,8 @@ vaultCmd.command("balance").description("Show LP share balance and asset value")
|
|
|
3241
3369
|
process.exit(1);
|
|
3242
3370
|
}
|
|
3243
3371
|
});
|
|
3244
|
-
var strategy = program.command("strategy");
|
|
3245
|
-
|
|
3246
|
-
const spinner = ora7("Loading strategies...").start();
|
|
3247
|
-
try {
|
|
3248
|
-
const strategies = await listStrategies(
|
|
3249
|
-
opts.type ? BigInt(opts.type) : void 0
|
|
3250
|
-
);
|
|
3251
|
-
spinner.stop();
|
|
3252
|
-
if (strategies.length === 0) {
|
|
3253
|
-
console.log(chalk7.dim("No strategies registered."));
|
|
3254
|
-
return;
|
|
3255
|
-
}
|
|
3256
|
-
console.log();
|
|
3257
|
-
console.log(chalk7.bold(`Strategies (${strategies.length})`));
|
|
3258
|
-
console.log(chalk7.dim("\u2500".repeat(70)));
|
|
3259
|
-
for (const s of strategies) {
|
|
3260
|
-
const status = s.active ? chalk7.green("active") : chalk7.red("inactive");
|
|
3261
|
-
console.log(` #${s.id} ${chalk7.bold(s.name)} [type: ${s.strategyTypeId}] ${status}`);
|
|
3262
|
-
console.log(` Creator: ${s.creator}`);
|
|
3263
|
-
console.log(` Implementation: ${s.implementation}`);
|
|
3264
|
-
if (s.metadataURI) {
|
|
3265
|
-
console.log(` Metadata: ${chalk7.dim(s.metadataURI)}`);
|
|
3266
|
-
}
|
|
3267
|
-
console.log();
|
|
3268
|
-
}
|
|
3269
|
-
} catch (err) {
|
|
3270
|
-
spinner.fail("Failed to load strategies");
|
|
3271
|
-
console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
|
|
3272
|
-
process.exit(1);
|
|
3273
|
-
}
|
|
3274
|
-
});
|
|
3275
|
-
strategy.command("info").description("Show strategy details").argument("<id>", "Strategy ID").action(async (idStr) => {
|
|
3276
|
-
const spinner = ora7("Loading strategy...").start();
|
|
3277
|
-
try {
|
|
3278
|
-
const s = await getStrategy(BigInt(idStr));
|
|
3279
|
-
spinner.stop();
|
|
3280
|
-
console.log();
|
|
3281
|
-
console.log(chalk7.bold(`Strategy #${s.id}`));
|
|
3282
|
-
console.log(chalk7.dim("\u2500".repeat(40)));
|
|
3283
|
-
console.log(` Name: ${s.name}`);
|
|
3284
|
-
console.log(` Type: ${s.strategyTypeId}`);
|
|
3285
|
-
console.log(` Active: ${s.active ? chalk7.green("yes") : chalk7.red("no")}`);
|
|
3286
|
-
console.log(` Creator: ${s.creator}`);
|
|
3287
|
-
console.log(` Implementation: ${s.implementation}`);
|
|
3288
|
-
if (s.metadataURI) {
|
|
3289
|
-
console.log(` Metadata: ${chalk7.dim(s.metadataURI)}`);
|
|
3290
|
-
}
|
|
3291
|
-
console.log();
|
|
3292
|
-
} catch (err) {
|
|
3293
|
-
spinner.fail("Failed to load strategy");
|
|
3294
|
-
console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
|
|
3295
|
-
process.exit(1);
|
|
3296
|
-
}
|
|
3297
|
-
});
|
|
3298
|
-
strategy.command("register").description("Register a new strategy on-chain").requiredOption("--implementation <address>", "Strategy contract address").requiredOption("--type <id>", "Strategy type ID").requiredOption("--name <name>", "Strategy name").option("--metadata <uri>", "Metadata URI (IPFS/Arweave)", "").action(async (opts) => {
|
|
3299
|
-
const spinner = ora7("Registering strategy...").start();
|
|
3300
|
-
try {
|
|
3301
|
-
const hash = await registerStrategy(
|
|
3302
|
-
opts.implementation,
|
|
3303
|
-
BigInt(opts.type),
|
|
3304
|
-
opts.name,
|
|
3305
|
-
opts.metadata
|
|
3306
|
-
);
|
|
3307
|
-
spinner.succeed(`Strategy registered: ${hash}`);
|
|
3308
|
-
console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
|
|
3309
|
-
} catch (err) {
|
|
3310
|
-
spinner.fail("Registration failed");
|
|
3311
|
-
console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
|
|
3312
|
-
process.exit(1);
|
|
3313
|
-
}
|
|
3314
|
-
});
|
|
3315
|
-
strategy.command("run").description("Execute the levered swap strategy").option("--vault <address>", "Vault address (default: from config)").requiredOption("--collateral <amount>", "WETH collateral amount (e.g. 1.0)").requiredOption("--borrow <amount>", "USDC to borrow against collateral").requiredOption("--token <address>", "Target token address to buy").option("--fee <tier>", "Uniswap fee tier in bps (500, 3000, 10000)", "500").option("--slippage <bps>", "Slippage tolerance in bps", "100").option("--execute", "Actually execute on-chain (default: simulate only)", false).action(async (opts) => {
|
|
3316
|
-
resolveVault(opts);
|
|
3317
|
-
await runLeveredSwap(opts);
|
|
3318
|
-
});
|
|
3372
|
+
var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
|
|
3373
|
+
registerStrategyTemplateCommands(strategy);
|
|
3319
3374
|
program.command("providers").description("List available DeFi providers").action(async () => {
|
|
3320
3375
|
const { MessariProvider, NansenProvider } = await import("./research-IUHVRHR3.js");
|
|
3321
3376
|
const providers = [new MoonwellProvider(), new UniswapProvider(), new MessariProvider(), new NansenProvider()];
|
|
@@ -3328,7 +3383,7 @@ ${info.name} (${info.type})`);
|
|
|
3328
3383
|
}
|
|
3329
3384
|
});
|
|
3330
3385
|
try {
|
|
3331
|
-
const { registerChatCommands } = await import("./chat-
|
|
3386
|
+
const { registerChatCommands } = await import("./chat-G5TRNY5S.js");
|
|
3332
3387
|
registerChatCommands(program);
|
|
3333
3388
|
} catch {
|
|
3334
3389
|
program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
|
|
@@ -3338,14 +3393,14 @@ try {
|
|
|
3338
3393
|
process.exit(1);
|
|
3339
3394
|
});
|
|
3340
3395
|
}
|
|
3341
|
-
var { registerSessionCommands } = await import("./session-
|
|
3396
|
+
var { registerSessionCommands } = await import("./session-VEF5BZIX.js");
|
|
3342
3397
|
registerSessionCommands(program);
|
|
3343
3398
|
registerVeniceCommands(program);
|
|
3344
3399
|
registerAllowanceCommands(program);
|
|
3345
3400
|
registerIdentityCommands(program);
|
|
3346
3401
|
registerProposalCommands(program);
|
|
3347
3402
|
registerGovernorCommands(program);
|
|
3348
|
-
var { registerResearchCommands } = await import("./research-
|
|
3403
|
+
var { registerResearchCommands } = await import("./research-FNH3VT57.js");
|
|
3349
3404
|
registerResearchCommands(program);
|
|
3350
3405
|
var configCmd = program.command("config");
|
|
3351
3406
|
configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").option("--rpc <url>", "Custom RPC URL for the active --chain network").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").action((opts) => {
|