@sherwoodagent/cli 0.15.3 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-A2ORZVU3.js → chat-XTOTPTGV.js} +4 -4
- package/dist/chunk-4GTOZMVG.js +458 -0
- package/dist/chunk-4GTOZMVG.js.map +1 -0
- package/dist/{chunk-GC5J54OC.js → chunk-E3UCNLU3.js} +120 -72
- package/dist/chunk-E3UCNLU3.js.map +1 -0
- package/dist/{chunk-LACUMLU4.js → chunk-E7KKGN3V.js} +2 -2
- package/dist/{chunk-AK7BD7KH.js → chunk-RAFAIAIE.js} +2 -2
- package/dist/{eas-V6B6XGBK.js → eas-MOPXU3QW.js} +3 -3
- package/dist/governor-J7WTADUX.js +79 -0
- package/dist/governor-J7WTADUX.js.map +1 -0
- package/dist/index.js +984 -834
- package/dist/index.js.map +1 -1
- package/dist/{research-63D7YID3.js → research-BYQZ2MLK.js} +3 -3
- package/dist/{session-3YRZI426.js → session-RDBY24HJ.js} +4 -4
- package/dist/{xmtp-BSTLCZWG.js → xmtp-2AHDKL2Q.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-GC5J54OC.js.map +0 -1
- /package/dist/{chat-A2ORZVU3.js.map → chat-XTOTPTGV.js.map} +0 -0
- /package/dist/{chunk-LACUMLU4.js.map → chunk-E7KKGN3V.js.map} +0 -0
- /package/dist/{chunk-AK7BD7KH.js.map → chunk-RAFAIAIE.js.map} +0 -0
- /package/dist/{eas-V6B6XGBK.js.map → eas-MOPXU3QW.js.map} +0 -0
- /package/dist/{research-63D7YID3.js.map → research-BYQZ2MLK.js.map} +0 -0
- /package/dist/{session-3YRZI426.js.map → session-RDBY24HJ.js.map} +0 -0
- /package/dist/{xmtp-BSTLCZWG.js.map → xmtp-2AHDKL2Q.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-4GTOZMVG.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-RAFAIAIE.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-E7KKGN3V.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-E3UCNLU3.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,717 @@ 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 };
|
|
336
|
+
];
|
|
337
|
+
function buildInitData3(params) {
|
|
338
|
+
return encodeAbiParameters3(INIT_PARAMS_TYPES2, [params]);
|
|
331
339
|
}
|
|
332
|
-
function
|
|
333
|
-
return
|
|
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
|
|
367
|
+
}
|
|
368
|
+
];
|
|
334
369
|
}
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
|
344
379
|
}
|
|
345
|
-
|
|
346
|
-
return concat(parts);
|
|
380
|
+
];
|
|
347
381
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
382
|
+
|
|
383
|
+
// src/strategies/wsteth-moonwell-template.ts
|
|
384
|
+
import { encodeAbiParameters as encodeAbiParameters4, encodeFunctionData as encodeFunctionData4 } from "viem";
|
|
385
|
+
var INIT_PARAMS_TYPES3 = [
|
|
386
|
+
{
|
|
387
|
+
type: "tuple",
|
|
388
|
+
components: [
|
|
389
|
+
{ name: "weth", type: "address" },
|
|
390
|
+
{ name: "wsteth", type: "address" },
|
|
391
|
+
{ name: "mwsteth", type: "address" },
|
|
392
|
+
{ name: "aeroRouter", type: "address" },
|
|
393
|
+
{ name: "aeroFactory", type: "address" },
|
|
394
|
+
{ name: "supplyAmount", type: "uint256" },
|
|
395
|
+
{ name: "minWstethOut", type: "uint256" },
|
|
396
|
+
{ name: "minWethOut", type: "uint256" },
|
|
397
|
+
{ name: "deadlineOffset", type: "uint256" }
|
|
398
|
+
]
|
|
361
399
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
data
|
|
366
|
-
});
|
|
367
|
-
return { amountOut, sqrtPriceX96After: 0n, gasEstimate };
|
|
400
|
+
];
|
|
401
|
+
function buildInitData4(params) {
|
|
402
|
+
return encodeAbiParameters4(INIT_PARAMS_TYPES3, [params]);
|
|
368
403
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
404
|
+
function buildExecuteCalls4(clone, weth, supplyAmount) {
|
|
405
|
+
return [
|
|
406
|
+
{
|
|
407
|
+
target: weth,
|
|
408
|
+
data: encodeFunctionData4({
|
|
409
|
+
abi: ERC20_ABI,
|
|
410
|
+
functionName: "approve",
|
|
411
|
+
args: [clone, supplyAmount]
|
|
412
|
+
}),
|
|
413
|
+
value: 0n
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
target: clone,
|
|
417
|
+
data: encodeFunctionData4({
|
|
418
|
+
abi: BASE_STRATEGY_ABI,
|
|
419
|
+
functionName: "execute"
|
|
420
|
+
}),
|
|
421
|
+
value: 0n
|
|
422
|
+
}
|
|
423
|
+
];
|
|
424
|
+
}
|
|
425
|
+
function buildSettleCalls4(clone) {
|
|
426
|
+
return [
|
|
427
|
+
{
|
|
428
|
+
target: clone,
|
|
429
|
+
data: encodeFunctionData4({
|
|
430
|
+
abi: BASE_STRATEGY_ABI,
|
|
431
|
+
functionName: "settle"
|
|
432
|
+
}),
|
|
433
|
+
value: 0n
|
|
434
|
+
}
|
|
435
|
+
];
|
|
376
436
|
}
|
|
377
437
|
|
|
378
|
-
// src/commands/strategy-
|
|
379
|
-
var
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
438
|
+
// src/commands/strategy-template.ts
|
|
439
|
+
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
440
|
+
var TEMPLATES = [
|
|
441
|
+
{
|
|
442
|
+
name: "Moonwell Supply",
|
|
443
|
+
key: "moonwell-supply",
|
|
444
|
+
description: "Supply tokens to Moonwell lending market, earn yield",
|
|
445
|
+
addressKey: "MOONWELL_SUPPLY"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "Aerodrome LP",
|
|
449
|
+
key: "aerodrome-lp",
|
|
450
|
+
description: "Provide liquidity on Aerodrome DEX + optional gauge staking",
|
|
451
|
+
addressKey: "AERODROME_LP"
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "Venice Inference",
|
|
455
|
+
key: "venice-inference",
|
|
456
|
+
description: "Stake VVV for sVVV \u2014 Venice private AI inference",
|
|
457
|
+
addressKey: "VENICE_INFERENCE"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "wstETH Moonwell Yield",
|
|
461
|
+
key: "wsteth-moonwell",
|
|
462
|
+
description: "WETH \u2192 wstETH \u2192 Moonwell \u2014 stack Lido + lending yield",
|
|
463
|
+
addressKey: "WSTETH_MOONWELL"
|
|
464
|
+
}
|
|
465
|
+
];
|
|
466
|
+
function resolveTemplate(key) {
|
|
467
|
+
const def = TEMPLATES.find((t) => t.key === key);
|
|
468
|
+
if (!def) {
|
|
469
|
+
console.error(chalk.red(`Unknown template: ${key}`));
|
|
470
|
+
console.error(chalk.dim(`Available: ${TEMPLATES.map((t) => t.key).join(", ")}`));
|
|
384
471
|
process.exit(1);
|
|
385
472
|
}
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
console.error(chalk.red(`Invalid fee tier: ${opts.fee}. Valid: ${VALID_FEES.join(", ")}`));
|
|
473
|
+
const address = STRATEGY_TEMPLATES()[def.addressKey];
|
|
474
|
+
if (address === ZERO) {
|
|
475
|
+
console.error(chalk.red(`Template "${def.name}" not deployed on this network.`));
|
|
390
476
|
process.exit(1);
|
|
391
477
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
478
|
+
return { def, address };
|
|
479
|
+
}
|
|
480
|
+
async function buildInitDataForTemplate(templateKey, opts, vault) {
|
|
481
|
+
if (templateKey === "moonwell-supply") {
|
|
482
|
+
if (!opts.amount) {
|
|
483
|
+
console.error(chalk.red("--amount is required for moonwell-supply template"));
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
const token = opts.token || "USDC";
|
|
487
|
+
const underlying = resolveToken(token);
|
|
488
|
+
const mToken = resolveMToken(token);
|
|
489
|
+
const decimals = token.toUpperCase() === "USDC" ? 6 : 18;
|
|
490
|
+
const supplyAmount = parseUnits(opts.amount, decimals);
|
|
491
|
+
const minRedeem = parseUnits(opts.minRedeem || opts.amount, decimals);
|
|
492
|
+
return {
|
|
493
|
+
initData: buildInitData(underlying, mToken, supplyAmount, minRedeem),
|
|
494
|
+
asset: underlying,
|
|
495
|
+
assetAmount: supplyAmount
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
if (templateKey === "venice-inference") {
|
|
499
|
+
if (!opts.amount) {
|
|
500
|
+
console.error(chalk.red("--amount is required for venice-inference template"));
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
const assetSymbol = opts.asset || "USDC";
|
|
504
|
+
const asset = resolveToken(assetSymbol);
|
|
505
|
+
const vvv = VENICE().VVV;
|
|
506
|
+
const isDirect = asset.toLowerCase() === vvv.toLowerCase();
|
|
507
|
+
const decimals = assetSymbol.toUpperCase() === "USDC" ? 6 : 18;
|
|
508
|
+
const assetAmount = parseUnits(opts.amount, decimals);
|
|
509
|
+
const agent = opts.agent || getAccount().address;
|
|
510
|
+
const params = {
|
|
511
|
+
asset,
|
|
512
|
+
weth: isDirect ? ZERO : TOKENS().WETH,
|
|
513
|
+
vvv,
|
|
514
|
+
sVVV: VENICE().STAKING,
|
|
515
|
+
aeroRouter: isDirect ? ZERO : AERODROME().ROUTER,
|
|
516
|
+
aeroFactory: isDirect ? ZERO : AERODROME().FACTORY,
|
|
517
|
+
agent,
|
|
518
|
+
assetAmount,
|
|
519
|
+
minVVV: isDirect ? 0n : parseUnits(opts.minVvv || "0", 18),
|
|
520
|
+
deadlineOffset: 300n,
|
|
521
|
+
singleHop: !!opts.singleHop
|
|
522
|
+
};
|
|
523
|
+
return {
|
|
524
|
+
initData: buildInitData2(params),
|
|
525
|
+
asset,
|
|
526
|
+
assetAmount
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (templateKey === "aerodrome-lp") {
|
|
530
|
+
for (const flag of ["tokenA", "tokenB", "amountA", "amountB", "lpToken"]) {
|
|
531
|
+
if (!opts[flag]) {
|
|
532
|
+
console.error(chalk.red(`--${flag.replace(/([A-Z])/g, "-$1").toLowerCase()} is required for aerodrome-lp template`));
|
|
533
|
+
process.exit(1);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
const tokenA = opts.tokenA;
|
|
537
|
+
const tokenB = opts.tokenB;
|
|
538
|
+
const publicClient = getPublicClient();
|
|
539
|
+
const [decimalsA, decimalsB] = await Promise.all([
|
|
540
|
+
publicClient.readContract({ address: tokenA, abi: erc20Abi, functionName: "decimals" }),
|
|
541
|
+
publicClient.readContract({ address: tokenB, abi: erc20Abi, functionName: "decimals" })
|
|
408
542
|
]);
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
543
|
+
const amountA = parseUnits(opts.amountA, decimalsA);
|
|
544
|
+
const amountB = parseUnits(opts.amountB, decimalsB);
|
|
545
|
+
const minAOut = parseUnits(opts.minAOut || "0", decimalsA);
|
|
546
|
+
const minBOut = parseUnits(opts.minBOut || "0", decimalsB);
|
|
547
|
+
const params = {
|
|
548
|
+
tokenA,
|
|
549
|
+
tokenB,
|
|
550
|
+
stable: !!opts.stable,
|
|
551
|
+
factory: AERODROME().FACTORY,
|
|
552
|
+
router: AERODROME().ROUTER,
|
|
553
|
+
gauge: opts.gauge || ZERO,
|
|
554
|
+
lpToken: opts.lpToken,
|
|
555
|
+
amountADesired: amountA,
|
|
556
|
+
amountBDesired: amountB,
|
|
557
|
+
amountAMin: amountA,
|
|
558
|
+
// use desired as min for now
|
|
559
|
+
amountBMin: amountB,
|
|
560
|
+
minAmountAOut: minAOut,
|
|
561
|
+
minAmountBOut: minBOut
|
|
562
|
+
};
|
|
563
|
+
return {
|
|
564
|
+
initData: buildInitData3(params),
|
|
565
|
+
asset: tokenA,
|
|
566
|
+
assetAmount: amountA,
|
|
567
|
+
extraApprovals: [{ token: tokenB, amount: amountB }]
|
|
568
|
+
};
|
|
412
569
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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);
|
|
570
|
+
if (templateKey === "wsteth-moonwell") {
|
|
571
|
+
if (!opts.amount) {
|
|
572
|
+
console.error(chalk.red("--amount is required for wsteth-moonwell template"));
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
const supplyAmount = parseUnits(opts.amount, 18);
|
|
576
|
+
const slippageBps = BigInt(opts.slippage || "500");
|
|
577
|
+
const minWstethOut = supplyAmount - supplyAmount * slippageBps / 10000n;
|
|
578
|
+
const minWethOut = supplyAmount - supplyAmount * slippageBps / 10000n;
|
|
579
|
+
const params = {
|
|
580
|
+
weth: TOKENS().WETH,
|
|
581
|
+
wsteth: TOKENS().wstETH,
|
|
582
|
+
mwsteth: MOONWELL().mWstETH,
|
|
583
|
+
aeroRouter: AERODROME().ROUTER,
|
|
584
|
+
aeroFactory: AERODROME().FACTORY,
|
|
585
|
+
supplyAmount,
|
|
586
|
+
minWstethOut,
|
|
587
|
+
minWethOut,
|
|
588
|
+
deadlineOffset: 300n
|
|
589
|
+
};
|
|
590
|
+
return {
|
|
591
|
+
initData: buildInitData4(params),
|
|
592
|
+
asset: TOKENS().WETH,
|
|
593
|
+
assetAmount: supplyAmount
|
|
594
|
+
};
|
|
443
595
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
596
|
+
throw new Error(`No init builder for template: ${templateKey}`);
|
|
597
|
+
}
|
|
598
|
+
function buildCallsForTemplate(templateKey, clone, asset, assetAmount, extraApprovals) {
|
|
599
|
+
if (templateKey === "moonwell-supply") {
|
|
600
|
+
return {
|
|
601
|
+
executeCalls: buildExecuteCalls(clone, asset, assetAmount),
|
|
602
|
+
settleCalls: buildSettleCalls(clone)
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
if (templateKey === "venice-inference") {
|
|
606
|
+
return {
|
|
607
|
+
executeCalls: buildExecuteCalls2(clone, asset, assetAmount),
|
|
608
|
+
settleCalls: buildSettleCalls2(clone)
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
if (templateKey === "aerodrome-lp") {
|
|
612
|
+
const tokenB = extraApprovals?.[0]?.token ?? ZERO;
|
|
613
|
+
const amountB = extraApprovals?.[0]?.amount ?? 0n;
|
|
614
|
+
return {
|
|
615
|
+
executeCalls: buildExecuteCalls3(clone, asset, assetAmount, tokenB, amountB),
|
|
616
|
+
settleCalls: buildSettleCalls3(clone)
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
if (templateKey === "wsteth-moonwell") {
|
|
620
|
+
return {
|
|
621
|
+
executeCalls: buildExecuteCalls4(clone, asset, assetAmount),
|
|
622
|
+
settleCalls: buildSettleCalls4(clone)
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
throw new Error(`No call builder for template: ${templateKey}`);
|
|
626
|
+
}
|
|
627
|
+
function resolveToken(symbolOrAddress) {
|
|
628
|
+
if (isAddress(symbolOrAddress)) return symbolOrAddress;
|
|
629
|
+
const upper = symbolOrAddress.toUpperCase();
|
|
630
|
+
const tokens = TOKENS();
|
|
631
|
+
const tokenMap = {
|
|
632
|
+
USDC: tokens.USDC,
|
|
633
|
+
WETH: tokens.WETH,
|
|
634
|
+
DAI: tokens.DAI,
|
|
635
|
+
AERO: tokens.AERO,
|
|
636
|
+
VVV: VENICE().VVV
|
|
454
637
|
};
|
|
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;
|
|
638
|
+
const addr = tokenMap[upper];
|
|
639
|
+
if (!addr || addr === ZERO) {
|
|
640
|
+
console.error(chalk.red(`Unknown token: ${symbolOrAddress}`));
|
|
641
|
+
process.exit(1);
|
|
465
642
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
643
|
+
return addr;
|
|
644
|
+
}
|
|
645
|
+
function resolveMToken(tokenSymbol) {
|
|
646
|
+
const upper = tokenSymbol.toUpperCase();
|
|
647
|
+
const moonwell = MOONWELL();
|
|
648
|
+
const mTokenMap = {
|
|
649
|
+
USDC: moonwell.mUSDC,
|
|
650
|
+
WETH: moonwell.mWETH
|
|
651
|
+
};
|
|
652
|
+
const addr = mTokenMap[upper];
|
|
653
|
+
if (!addr || addr === ZERO) {
|
|
654
|
+
console.error(chalk.red(`No Moonwell market for: ${tokenSymbol}`));
|
|
474
655
|
process.exit(1);
|
|
475
656
|
}
|
|
657
|
+
return addr;
|
|
658
|
+
}
|
|
659
|
+
function serializeCalls(calls) {
|
|
660
|
+
return JSON.stringify(
|
|
661
|
+
calls.map((c) => ({
|
|
662
|
+
target: c.target,
|
|
663
|
+
data: c.data,
|
|
664
|
+
value: c.value.toString()
|
|
665
|
+
})),
|
|
666
|
+
null,
|
|
667
|
+
2
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
function registerStrategyTemplateCommands(strategy2) {
|
|
671
|
+
strategy2.command("list").description("List available strategy templates").action(() => {
|
|
672
|
+
const templates = STRATEGY_TEMPLATES();
|
|
673
|
+
console.log();
|
|
674
|
+
console.log(chalk.bold("Strategy Templates"));
|
|
675
|
+
console.log(chalk.dim("\u2500".repeat(60)));
|
|
676
|
+
for (const t of TEMPLATES) {
|
|
677
|
+
const addr = templates[t.addressKey];
|
|
678
|
+
const deployed = addr !== ZERO;
|
|
679
|
+
console.log();
|
|
680
|
+
console.log(` ${chalk.bold(t.name)} (${chalk.cyan(t.key)})`);
|
|
681
|
+
console.log(` ${t.description}`);
|
|
682
|
+
console.log(` Template: ${deployed ? chalk.green(addr) : chalk.red("not deployed")}`);
|
|
683
|
+
}
|
|
684
|
+
console.log();
|
|
685
|
+
console.log(chalk.dim("Clone a template: sherwood strategy clone <template> --vault <addr> ..."));
|
|
686
|
+
console.log(chalk.dim("Full proposal: sherwood strategy propose <template> --vault <addr> ..."));
|
|
687
|
+
console.log();
|
|
688
|
+
});
|
|
689
|
+
strategy2.command("clone").description("Clone a strategy template and initialize it").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell").requiredOption("--vault <address>", "Vault address").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").option("--slippage <bps>", "Slippage tolerance in bps (wstETH, default: 500 = 5%)").action(async (templateKey, opts) => {
|
|
690
|
+
const vault = opts.vault;
|
|
691
|
+
if (!isAddress(vault)) {
|
|
692
|
+
console.error(chalk.red("Invalid vault address"));
|
|
693
|
+
process.exit(1);
|
|
694
|
+
}
|
|
695
|
+
const { def, address: templateAddr } = resolveTemplate(templateKey);
|
|
696
|
+
const cloneSpinner = ora(`Cloning ${def.name} template...`).start();
|
|
697
|
+
let clone;
|
|
698
|
+
let cloneHash;
|
|
699
|
+
try {
|
|
700
|
+
const result = await cloneTemplate(templateAddr);
|
|
701
|
+
clone = result.clone;
|
|
702
|
+
cloneHash = result.hash;
|
|
703
|
+
cloneSpinner.succeed(`Cloned: ${chalk.green(clone)}`);
|
|
704
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(cloneHash)}`));
|
|
705
|
+
} catch (err) {
|
|
706
|
+
cloneSpinner.fail("Clone failed");
|
|
707
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
708
|
+
process.exit(1);
|
|
709
|
+
}
|
|
710
|
+
const initSpinner = ora("Initializing strategy...").start();
|
|
711
|
+
try {
|
|
712
|
+
const { initData } = await buildInitDataForTemplate(templateKey, opts, vault);
|
|
713
|
+
const account = getAccount();
|
|
714
|
+
const wallet = getWalletClient();
|
|
715
|
+
const initHash = await wallet.writeContract({
|
|
716
|
+
account,
|
|
717
|
+
chain: getChain(),
|
|
718
|
+
address: clone,
|
|
719
|
+
abi: BASE_STRATEGY_ABI,
|
|
720
|
+
functionName: "initialize",
|
|
721
|
+
args: [vault, account.address, initData]
|
|
722
|
+
});
|
|
723
|
+
await getPublicClient().waitForTransactionReceipt({ hash: initHash });
|
|
724
|
+
initSpinner.succeed("Initialized");
|
|
725
|
+
} catch (err) {
|
|
726
|
+
initSpinner.fail("Initialize failed");
|
|
727
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
728
|
+
process.exit(1);
|
|
729
|
+
}
|
|
730
|
+
console.log();
|
|
731
|
+
console.log(chalk.bold("Strategy clone ready:"), chalk.green(clone));
|
|
732
|
+
console.log(chalk.dim("Use this address in your proposal batch calls."));
|
|
733
|
+
console.log();
|
|
734
|
+
});
|
|
735
|
+
strategy2.command("propose").description("Clone + init + build calls + submit governance proposal (all-in-one)").argument("<template>", "Template: moonwell-supply, aerodrome-lp, venice-inference, wsteth-moonwell").requiredOption("--vault <address>", "Vault address").option("--write-calls <dir>", "Write execute/settle JSON to directory (skip proposal submission)").option("--name <name>", "Proposal name").option("--description <text>", "Proposal description").option("--performance-fee <bps>", "Agent fee in bps").option("--duration <duration>", "Strategy duration (7d, 24h, etc.)").option("--amount <n>", "Asset amount to deploy").option("--min-redeem <n>", "Min asset on settlement (Moonwell)").option("--token <symbol>", "Asset token symbol (default: USDC)").option("--asset <symbol>", "Asset token (USDC, VVV, or address)").option("--agent <address>", "Agent wallet (Venice, default: your wallet)").option("--min-vvv <n>", "Min VVV from swap (Venice)").option("--single-hop", "Single-hop Aerodrome swap (Venice)").option("--token-a <address>", "Token A (Aerodrome)").option("--token-b <address>", "Token B (Aerodrome)").option("--amount-a <n>", "Token A amount (Aerodrome)").option("--amount-b <n>", "Token B amount (Aerodrome)").option("--stable", "Stable pool (Aerodrome)").option("--gauge <address>", "Gauge address (Aerodrome)").option("--lp-token <address>", "LP token address (Aerodrome)").option("--min-a-out <n>", "Min token A on settle (Aerodrome)").option("--min-b-out <n>", "Min token B on settle (Aerodrome)").option("--slippage <bps>", "Slippage tolerance in bps (wstETH, default: 500 = 5%)").action(async (templateKey, opts) => {
|
|
736
|
+
const vault = opts.vault;
|
|
737
|
+
if (!isAddress(vault)) {
|
|
738
|
+
console.error(chalk.red("Invalid vault address"));
|
|
739
|
+
process.exit(1);
|
|
740
|
+
}
|
|
741
|
+
const { def, address: templateAddr } = resolveTemplate(templateKey);
|
|
742
|
+
const cloneSpinner = ora(`Cloning ${def.name} template...`).start();
|
|
743
|
+
let clone;
|
|
744
|
+
try {
|
|
745
|
+
const result = await cloneTemplate(templateAddr);
|
|
746
|
+
clone = result.clone;
|
|
747
|
+
cloneSpinner.succeed(`Cloned: ${chalk.green(clone)}`);
|
|
748
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(result.hash)}`));
|
|
749
|
+
} catch (err) {
|
|
750
|
+
cloneSpinner.fail("Clone failed");
|
|
751
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
752
|
+
process.exit(1);
|
|
753
|
+
}
|
|
754
|
+
const initSpinner = ora("Initializing strategy...").start();
|
|
755
|
+
let asset;
|
|
756
|
+
let assetAmount;
|
|
757
|
+
let extraApprovals;
|
|
758
|
+
try {
|
|
759
|
+
const built = await buildInitDataForTemplate(templateKey, opts, vault);
|
|
760
|
+
asset = built.asset;
|
|
761
|
+
assetAmount = built.assetAmount;
|
|
762
|
+
extraApprovals = built.extraApprovals;
|
|
763
|
+
const account2 = getAccount();
|
|
764
|
+
const wallet = getWalletClient();
|
|
765
|
+
const initHash = await wallet.writeContract({
|
|
766
|
+
account: account2,
|
|
767
|
+
chain: getChain(),
|
|
768
|
+
address: clone,
|
|
769
|
+
abi: BASE_STRATEGY_ABI,
|
|
770
|
+
functionName: "initialize",
|
|
771
|
+
args: [vault, account2.address, built.initData]
|
|
772
|
+
});
|
|
773
|
+
await getPublicClient().waitForTransactionReceipt({ hash: initHash });
|
|
774
|
+
initSpinner.succeed("Initialized");
|
|
775
|
+
} catch (err) {
|
|
776
|
+
initSpinner.fail("Initialize failed");
|
|
777
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
const { executeCalls, settleCalls } = buildCallsForTemplate(
|
|
781
|
+
templateKey,
|
|
782
|
+
clone,
|
|
783
|
+
asset,
|
|
784
|
+
assetAmount,
|
|
785
|
+
extraApprovals
|
|
786
|
+
);
|
|
787
|
+
console.log();
|
|
788
|
+
console.log(chalk.bold(`Execute calls (${executeCalls.length}):`));
|
|
789
|
+
console.log(formatBatch(executeCalls));
|
|
790
|
+
console.log(chalk.bold(`Settle calls (${settleCalls.length}):`));
|
|
791
|
+
console.log(formatBatch(settleCalls));
|
|
792
|
+
if (opts.writeCalls) {
|
|
793
|
+
const dir = resolve(opts.writeCalls);
|
|
794
|
+
mkdirSync(dir, { recursive: true });
|
|
795
|
+
const execPath = resolve(dir, "execute.json");
|
|
796
|
+
const settlePath = resolve(dir, "settle.json");
|
|
797
|
+
writeFileSync(execPath, serializeCalls(executeCalls));
|
|
798
|
+
writeFileSync(settlePath, serializeCalls(settleCalls));
|
|
799
|
+
console.log();
|
|
800
|
+
console.log(chalk.green(`Execute calls: ${execPath}`));
|
|
801
|
+
console.log(chalk.green(`Settle calls: ${settlePath}`));
|
|
802
|
+
console.log(chalk.green(`Clone address: ${clone}`));
|
|
803
|
+
console.log();
|
|
804
|
+
console.log(chalk.dim("Submit with:"));
|
|
805
|
+
console.log(chalk.dim(` sherwood proposal create \\`));
|
|
806
|
+
console.log(chalk.dim(` --vault ${vault} \\`));
|
|
807
|
+
console.log(chalk.dim(` --name "..." --description "..." \\`));
|
|
808
|
+
console.log(chalk.dim(` --performance-fee 0 --duration 7d \\`));
|
|
809
|
+
console.log(chalk.dim(` --execute-calls ${execPath} \\`));
|
|
810
|
+
console.log(chalk.dim(` --settle-calls ${settlePath}`));
|
|
811
|
+
if (templateKey === "venice-inference") {
|
|
812
|
+
console.log();
|
|
813
|
+
console.log(chalk.yellow("Reminder: before settlement, agent must approve repayment:"));
|
|
814
|
+
console.log(chalk.yellow(` asset.approve(${clone}, <repaymentAmount>)`));
|
|
815
|
+
console.log(chalk.yellow(" Agent can update repayment via strategy.updateParams(newRepayment, 0, 0)"));
|
|
816
|
+
}
|
|
817
|
+
console.log();
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
if (!opts.name || !opts.performanceFee || !opts.duration) {
|
|
821
|
+
console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
|
|
822
|
+
process.exit(1);
|
|
823
|
+
}
|
|
824
|
+
const { propose: propose2 } = await import("./governor-J7WTADUX.js");
|
|
825
|
+
const { pinJSON } = await import("./ipfs-6XVOOHSR.js");
|
|
826
|
+
const { parseDuration: parseDuration2 } = await import("./governor-J7WTADUX.js");
|
|
827
|
+
const performanceFeeBps = BigInt(opts.performanceFee);
|
|
828
|
+
if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
|
|
829
|
+
console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
|
|
830
|
+
process.exit(1);
|
|
831
|
+
}
|
|
832
|
+
const strategyDuration = parseDuration2(opts.duration);
|
|
833
|
+
const account = getAccount();
|
|
834
|
+
const metaSpinner = ora("Pinning metadata to IPFS...").start();
|
|
835
|
+
let metadataURI;
|
|
836
|
+
try {
|
|
837
|
+
const metadata = {
|
|
838
|
+
name: opts.name,
|
|
839
|
+
description: opts.description || "",
|
|
840
|
+
proposer: account.address,
|
|
841
|
+
vault,
|
|
842
|
+
strategyClone: clone,
|
|
843
|
+
template: def.key,
|
|
844
|
+
performanceFeeBps: Number(performanceFeeBps),
|
|
845
|
+
strategyDuration: Number(strategyDuration),
|
|
846
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
847
|
+
};
|
|
848
|
+
metadataURI = await pinJSON(metadata, opts.name);
|
|
849
|
+
metaSpinner.succeed(`Metadata pinned: ${metadataURI}`);
|
|
850
|
+
} catch (err) {
|
|
851
|
+
metaSpinner.fail("IPFS pin failed");
|
|
852
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
853
|
+
process.exit(1);
|
|
854
|
+
}
|
|
855
|
+
const proposeSpinner = ora("Submitting proposal...").start();
|
|
856
|
+
try {
|
|
857
|
+
const { hash, proposalId } = await propose2(
|
|
858
|
+
vault,
|
|
859
|
+
metadataURI,
|
|
860
|
+
performanceFeeBps,
|
|
861
|
+
strategyDuration,
|
|
862
|
+
executeCalls,
|
|
863
|
+
settleCalls
|
|
864
|
+
);
|
|
865
|
+
proposeSpinner.succeed(`Proposal #${proposalId} created`);
|
|
866
|
+
console.log(chalk.dim(` Tx: ${getExplorerUrl(hash)}`));
|
|
867
|
+
console.log(chalk.dim(` Clone: ${clone}`));
|
|
868
|
+
} catch (err) {
|
|
869
|
+
proposeSpinner.fail("Proposal failed");
|
|
870
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
871
|
+
process.exit(1);
|
|
872
|
+
}
|
|
873
|
+
if (templateKey === "venice-inference") {
|
|
874
|
+
console.log();
|
|
875
|
+
console.log(chalk.yellow("Next steps:"));
|
|
876
|
+
console.log(chalk.yellow(" 1. After execution: sherwood venice provision"));
|
|
877
|
+
console.log(chalk.yellow(" 2. Use inference: sherwood venice infer --model <id> --prompt '...'"));
|
|
878
|
+
console.log(chalk.yellow(" 3. Before settlement: approve repayment (principal + profit):"));
|
|
879
|
+
console.log(chalk.yellow(` asset.approve(${clone}, <repaymentAmount>)`));
|
|
880
|
+
}
|
|
881
|
+
console.log();
|
|
882
|
+
});
|
|
476
883
|
}
|
|
477
884
|
|
|
478
885
|
// src/lib/factory.ts
|
|
@@ -652,74 +1059,83 @@ async function getActiveSyndicates2(creator) {
|
|
|
652
1059
|
return data.syndicates;
|
|
653
1060
|
}
|
|
654
1061
|
|
|
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) {
|
|
1062
|
+
// src/commands/venice.ts
|
|
1063
|
+
import { parseUnits as parseUnits4, formatUnits as formatUnits2, isAddress as isAddress2 } from "viem";
|
|
1064
|
+
import chalk2 from "chalk";
|
|
1065
|
+
import ora2 from "ora";
|
|
1066
|
+
|
|
1067
|
+
// src/lib/quote.ts
|
|
1068
|
+
import { encodeFunctionData as encodeFunctionData5, decodeFunctionResult, concat as concat2, pad, numberToHex } from "viem";
|
|
1069
|
+
async function getQuote(params) {
|
|
671
1070
|
const client = getPublicClient();
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
1071
|
+
const calldata = encodeFunctionData5({
|
|
1072
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1073
|
+
functionName: "quoteExactInputSingle",
|
|
1074
|
+
args: [
|
|
1075
|
+
{
|
|
1076
|
+
tokenIn: params.tokenIn,
|
|
1077
|
+
tokenOut: params.tokenOut,
|
|
1078
|
+
amountIn: params.amountIn,
|
|
1079
|
+
fee: params.fee,
|
|
1080
|
+
sqrtPriceLimitX96: 0n
|
|
1081
|
+
}
|
|
1082
|
+
]
|
|
677
1083
|
});
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
1084
|
+
const { data } = await client.call({
|
|
1085
|
+
to: UNISWAP().QUOTER_V2,
|
|
1086
|
+
data: calldata
|
|
1087
|
+
});
|
|
1088
|
+
if (!data) {
|
|
1089
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this pair/fee");
|
|
1090
|
+
}
|
|
1091
|
+
const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({
|
|
1092
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1093
|
+
functionName: "quoteExactInputSingle",
|
|
1094
|
+
data
|
|
1095
|
+
});
|
|
1096
|
+
return { amountOut, sqrtPriceX96After, gasEstimate };
|
|
687
1097
|
}
|
|
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));
|
|
1098
|
+
function applySlippage(amountOut, slippageBps) {
|
|
1099
|
+
return amountOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
1100
|
+
}
|
|
1101
|
+
function encodeSwapPath(tokens, fees) {
|
|
1102
|
+
if (tokens.length < 2 || fees.length !== tokens.length - 1) {
|
|
1103
|
+
throw new Error("Invalid path: need at least 2 tokens and (tokens-1) fees");
|
|
1104
|
+
}
|
|
1105
|
+
const parts = [];
|
|
1106
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
1107
|
+
parts.push(tokens[i].toLowerCase());
|
|
1108
|
+
if (i < fees.length) {
|
|
1109
|
+
parts.push(pad(numberToHex(fees[i]), { size: 3 }));
|
|
1110
|
+
}
|
|
706
1111
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1112
|
+
return concat2(parts);
|
|
1113
|
+
}
|
|
1114
|
+
async function getMultiHopQuote(params) {
|
|
1115
|
+
const client = getPublicClient();
|
|
1116
|
+
const calldata = encodeFunctionData5({
|
|
1117
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1118
|
+
functionName: "quoteExactInput",
|
|
1119
|
+
args: [params.path, params.amountIn]
|
|
1120
|
+
});
|
|
1121
|
+
const { data } = await client.call({
|
|
1122
|
+
to: UNISWAP().QUOTER_V2,
|
|
1123
|
+
data: calldata
|
|
1124
|
+
});
|
|
1125
|
+
if (!data) {
|
|
1126
|
+
throw new Error("Quoter returned no data \u2014 pool may not exist for this path");
|
|
711
1127
|
}
|
|
712
|
-
|
|
1128
|
+
const [amountOut, , , gasEstimate] = decodeFunctionResult({
|
|
1129
|
+
abi: UNISWAP_QUOTER_V2_ABI,
|
|
1130
|
+
functionName: "quoteExactInput",
|
|
1131
|
+
data
|
|
1132
|
+
});
|
|
1133
|
+
return { amountOut, sqrtPriceX96After: 0n, gasEstimate };
|
|
713
1134
|
}
|
|
714
1135
|
|
|
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
1136
|
// src/strategies/venice-fund.ts
|
|
721
|
-
import { encodeFunctionData as
|
|
722
|
-
var
|
|
1137
|
+
import { encodeFunctionData as encodeFunctionData6, parseUnits as parseUnits3 } from "viem";
|
|
1138
|
+
var ERC20_ABI2 = [
|
|
723
1139
|
{
|
|
724
1140
|
name: "approve",
|
|
725
1141
|
type: "function",
|
|
@@ -783,17 +1199,17 @@ var STAKING_ABI = [
|
|
|
783
1199
|
}
|
|
784
1200
|
];
|
|
785
1201
|
function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minVVV, swapPath) {
|
|
786
|
-
const
|
|
787
|
-
if (VENICE().VVV ===
|
|
1202
|
+
const ZERO2 = "0x0000000000000000000000000000000000000000";
|
|
1203
|
+
if (VENICE().VVV === ZERO2 || VENICE().STAKING === ZERO2) {
|
|
788
1204
|
throw new Error("Venice (VVV/sVVV) is not deployed on this network \u2014 venice fund requires Venice staking contracts");
|
|
789
1205
|
}
|
|
790
|
-
const assetAmount =
|
|
1206
|
+
const assetAmount = parseUnits3(config.amount, assetDecimals);
|
|
791
1207
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
792
1208
|
const calls = [];
|
|
793
1209
|
calls.push({
|
|
794
1210
|
target: assetAddress,
|
|
795
|
-
data:
|
|
796
|
-
abi:
|
|
1211
|
+
data: encodeFunctionData6({
|
|
1212
|
+
abi: ERC20_ABI2,
|
|
797
1213
|
functionName: "approve",
|
|
798
1214
|
args: [UNISWAP().SWAP_ROUTER, assetAmount]
|
|
799
1215
|
}),
|
|
@@ -802,7 +1218,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
802
1218
|
if (isWeth) {
|
|
803
1219
|
calls.push({
|
|
804
1220
|
target: UNISWAP().SWAP_ROUTER,
|
|
805
|
-
data:
|
|
1221
|
+
data: encodeFunctionData6({
|
|
806
1222
|
abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
|
|
807
1223
|
functionName: "exactInputSingle",
|
|
808
1224
|
args: [
|
|
@@ -822,7 +1238,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
822
1238
|
} else {
|
|
823
1239
|
calls.push({
|
|
824
1240
|
target: UNISWAP().SWAP_ROUTER,
|
|
825
|
-
data:
|
|
1241
|
+
data: encodeFunctionData6({
|
|
826
1242
|
abi: SWAP_ROUTER_EXACT_INPUT_ABI,
|
|
827
1243
|
functionName: "exactInput",
|
|
828
1244
|
args: [
|
|
@@ -839,8 +1255,8 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
839
1255
|
}
|
|
840
1256
|
calls.push({
|
|
841
1257
|
target: VENICE().VVV,
|
|
842
|
-
data:
|
|
843
|
-
abi:
|
|
1258
|
+
data: encodeFunctionData6({
|
|
1259
|
+
abi: ERC20_ABI2,
|
|
844
1260
|
functionName: "approve",
|
|
845
1261
|
args: [VENICE().STAKING, minVVV]
|
|
846
1262
|
}),
|
|
@@ -850,7 +1266,7 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
850
1266
|
for (const agent of agents) {
|
|
851
1267
|
calls.push({
|
|
852
1268
|
target: VENICE().STAKING,
|
|
853
|
-
data:
|
|
1269
|
+
data: encodeFunctionData6({
|
|
854
1270
|
abi: STAKING_ABI,
|
|
855
1271
|
functionName: "stake",
|
|
856
1272
|
args: [agent, perAgent]
|
|
@@ -865,16 +1281,22 @@ function buildFundBatch(config, vaultAddress, agents, assetAddress, assetDecimal
|
|
|
865
1281
|
var VENICE_API_BASE = "https://api.venice.ai/api/v1";
|
|
866
1282
|
async function provisionApiKey() {
|
|
867
1283
|
const account = getAccount();
|
|
868
|
-
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key
|
|
1284
|
+
const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
1285
|
+
signal: AbortSignal.timeout(15e3)
|
|
1286
|
+
});
|
|
869
1287
|
if (!tokenRes.ok) {
|
|
870
1288
|
throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
|
|
871
1289
|
}
|
|
872
1290
|
const tokenData = await tokenRes.json();
|
|
873
|
-
const token = tokenData
|
|
1291
|
+
const token = tokenData?.data?.token;
|
|
1292
|
+
if (!token) {
|
|
1293
|
+
throw new Error("Venice API returned no validation token");
|
|
1294
|
+
}
|
|
874
1295
|
const signature = await account.signMessage({ message: token });
|
|
875
1296
|
const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
|
|
876
1297
|
method: "POST",
|
|
877
1298
|
headers: { "Content-Type": "application/json" },
|
|
1299
|
+
signal: AbortSignal.timeout(15e3),
|
|
878
1300
|
body: JSON.stringify({
|
|
879
1301
|
address: account.address,
|
|
880
1302
|
signature,
|
|
@@ -888,28 +1310,92 @@ async function provisionApiKey() {
|
|
|
888
1310
|
throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
|
|
889
1311
|
}
|
|
890
1312
|
const keyData = await keyRes.json();
|
|
891
|
-
const apiKey = keyData
|
|
1313
|
+
const apiKey = keyData?.data?.apiKey;
|
|
1314
|
+
if (!apiKey) {
|
|
1315
|
+
throw new Error("Venice API returned no API key");
|
|
1316
|
+
}
|
|
892
1317
|
setVeniceApiKey(apiKey);
|
|
893
1318
|
return apiKey;
|
|
894
1319
|
}
|
|
895
|
-
async function checkApiKeyValid() {
|
|
1320
|
+
async function checkApiKeyValid() {
|
|
1321
|
+
const apiKey = getVeniceApiKey();
|
|
1322
|
+
if (!apiKey) return false;
|
|
1323
|
+
try {
|
|
1324
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
1325
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1326
|
+
signal: AbortSignal.timeout(15e3)
|
|
1327
|
+
});
|
|
1328
|
+
return res.ok;
|
|
1329
|
+
} catch {
|
|
1330
|
+
return false;
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
async function chatCompletion(opts) {
|
|
1334
|
+
const apiKey = getVeniceApiKey();
|
|
1335
|
+
if (!apiKey) {
|
|
1336
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
1337
|
+
}
|
|
1338
|
+
const body = {
|
|
1339
|
+
model: opts.model,
|
|
1340
|
+
messages: opts.messages
|
|
1341
|
+
};
|
|
1342
|
+
if (opts.temperature !== void 0) body.temperature = opts.temperature;
|
|
1343
|
+
if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
|
|
1344
|
+
const veniceParams = {};
|
|
1345
|
+
if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
|
|
1346
|
+
if (opts.disableThinking) veniceParams.disable_thinking = true;
|
|
1347
|
+
if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
|
|
1348
|
+
const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
|
|
1349
|
+
method: "POST",
|
|
1350
|
+
headers: {
|
|
1351
|
+
"Content-Type": "application/json",
|
|
1352
|
+
Authorization: `Bearer ${apiKey}`
|
|
1353
|
+
},
|
|
1354
|
+
signal: AbortSignal.timeout(12e4),
|
|
1355
|
+
// inference can be slow
|
|
1356
|
+
body: JSON.stringify(body)
|
|
1357
|
+
});
|
|
1358
|
+
if (!res.ok) {
|
|
1359
|
+
const errBody = await res.text();
|
|
1360
|
+
throw new Error(`Venice inference failed: ${res.status} ${errBody}`);
|
|
1361
|
+
}
|
|
1362
|
+
const data = await res.json();
|
|
1363
|
+
const choice = data.choices?.[0];
|
|
1364
|
+
if (!choice) {
|
|
1365
|
+
throw new Error("Venice returned no choices");
|
|
1366
|
+
}
|
|
1367
|
+
return {
|
|
1368
|
+
content: choice.message?.content ?? "",
|
|
1369
|
+
model: data.model ?? opts.model,
|
|
1370
|
+
usage: {
|
|
1371
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
1372
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
1373
|
+
totalTokens: data.usage?.total_tokens ?? 0
|
|
1374
|
+
}
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
async function listModels() {
|
|
896
1378
|
const apiKey = getVeniceApiKey();
|
|
897
|
-
if (!apiKey)
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
|
|
1379
|
+
if (!apiKey) {
|
|
1380
|
+
throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
|
|
1381
|
+
}
|
|
1382
|
+
const res = await fetch(`${VENICE_API_BASE}/models`, {
|
|
1383
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1384
|
+
signal: AbortSignal.timeout(15e3)
|
|
1385
|
+
});
|
|
1386
|
+
if (!res.ok) {
|
|
1387
|
+
throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
|
|
905
1388
|
}
|
|
1389
|
+
const data = await res.json();
|
|
1390
|
+
return (data.data ?? []).map((m) => m.id);
|
|
906
1391
|
}
|
|
907
1392
|
|
|
908
1393
|
// src/commands/venice.ts
|
|
909
|
-
|
|
1394
|
+
import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1395
|
+
var VALID_FEES = [500, 3e3, 1e4];
|
|
910
1396
|
function registerVeniceCommands(program2) {
|
|
911
1397
|
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) => {
|
|
1398
|
+
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
1399
|
const vaultAddress = opts.vault;
|
|
914
1400
|
if (!isAddress2(vaultAddress)) {
|
|
915
1401
|
console.error(chalk2.red(`Invalid vault address: ${opts.vault}`));
|
|
@@ -917,8 +1403,8 @@ function registerVeniceCommands(program2) {
|
|
|
917
1403
|
}
|
|
918
1404
|
const fee1 = Number(opts.fee1);
|
|
919
1405
|
const fee2 = Number(opts.fee2);
|
|
920
|
-
if (!
|
|
921
|
-
console.error(chalk2.red(`Invalid fee tier. Valid: ${
|
|
1406
|
+
if (!VALID_FEES.includes(fee1) || !VALID_FEES.includes(fee2)) {
|
|
1407
|
+
console.error(chalk2.red(`Invalid fee tier. Valid: ${VALID_FEES.join(", ")}`));
|
|
922
1408
|
process.exit(1);
|
|
923
1409
|
}
|
|
924
1410
|
const slippageBps = Number(opts.slippage);
|
|
@@ -951,7 +1437,7 @@ function registerVeniceCommands(program2) {
|
|
|
951
1437
|
console.error(chalk2.red("No agents registered in vault. Register agents first."));
|
|
952
1438
|
process.exit(1);
|
|
953
1439
|
}
|
|
954
|
-
const requestedAmount =
|
|
1440
|
+
const requestedAmount = parseUnits4(opts.amount, assetDecimals);
|
|
955
1441
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
956
1442
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
957
1443
|
console.log();
|
|
@@ -959,16 +1445,16 @@ function registerVeniceCommands(program2) {
|
|
|
959
1445
|
console.log(chalk2.dim("\u2500".repeat(40)));
|
|
960
1446
|
console.log(` Asset: ${assetSymbol} (${assetDecimals} decimals)`);
|
|
961
1447
|
console.log(` Amount: ${opts.amount} ${assetSymbol}`);
|
|
962
|
-
console.log(` Vault balance: ${
|
|
963
|
-
console.log(` Deposited: ${
|
|
964
|
-
console.log(` Profit: ${
|
|
1448
|
+
console.log(` Vault balance: ${formatUnits2(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
1449
|
+
console.log(` Deposited: ${formatUnits2(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
1450
|
+
console.log(` Profit: ${formatUnits2(profit, assetDecimals)} ${assetSymbol}`);
|
|
965
1451
|
console.log(` Agents: ${agents.length} (sVVV will be split equally)`);
|
|
966
1452
|
console.log(` Routing: ${isWeth ? `WETH \u2192 VVV (fee ${fee2})` : `${assetSymbol} \u2192 WETH (fee ${fee1}) \u2192 VVV (fee ${fee2})`}`);
|
|
967
1453
|
console.log(` Slippage: ${(slippageBps / 100).toFixed(2)}%`);
|
|
968
1454
|
console.log(` Vault: ${vaultAddress}`);
|
|
969
1455
|
console.log();
|
|
970
1456
|
if (requestedAmount > profit) {
|
|
971
|
-
console.warn(chalk2.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${
|
|
1457
|
+
console.warn(chalk2.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits2(profit, assetDecimals)})`));
|
|
972
1458
|
console.warn(chalk2.yellow(" This will use deposited capital, not just profits."));
|
|
973
1459
|
console.log();
|
|
974
1460
|
}
|
|
@@ -998,7 +1484,7 @@ function registerVeniceCommands(program2) {
|
|
|
998
1484
|
}
|
|
999
1485
|
minOut = applySlippage(amountOut, slippageBps);
|
|
1000
1486
|
quoteSpinner.succeed(
|
|
1001
|
-
`Quote: ${
|
|
1487
|
+
`Quote: ${formatUnits2(amountOut, 18)} VVV (min: ${formatUnits2(minOut, 18)}, per agent: ${formatUnits2(minOut / BigInt(agents.length), 18)})`
|
|
1002
1488
|
);
|
|
1003
1489
|
} catch (err) {
|
|
1004
1490
|
quoteSpinner.fail("Failed to fetch quote");
|
|
@@ -1016,9 +1502,24 @@ function registerVeniceCommands(program2) {
|
|
|
1016
1502
|
console.log(chalk2.bold(`Batch calls (${calls.length}):`));
|
|
1017
1503
|
console.log(formatBatch(calls));
|
|
1018
1504
|
console.log();
|
|
1505
|
+
if (opts.writeCalls) {
|
|
1506
|
+
const callsJson = calls.map((c) => ({
|
|
1507
|
+
target: c.target,
|
|
1508
|
+
data: c.data,
|
|
1509
|
+
value: c.value.toString()
|
|
1510
|
+
}));
|
|
1511
|
+
writeFileSync2(opts.writeCalls, JSON.stringify(callsJson, null, 2));
|
|
1512
|
+
const settlePath = `${opts.writeCalls}.settle.json`;
|
|
1513
|
+
writeFileSync2(settlePath, "[]");
|
|
1514
|
+
console.log(chalk2.green(`Execute calls written to: ${opts.writeCalls}`));
|
|
1515
|
+
console.log(chalk2.green(`Settlement calls written to: ${settlePath}`));
|
|
1516
|
+
console.log();
|
|
1517
|
+
console.log(chalk2.dim("Use with: sherwood proposal create --execute-calls <path> --settle-calls <path>"));
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1019
1520
|
if (!opts.execute) {
|
|
1020
1521
|
console.log();
|
|
1021
|
-
console.log(chalk2.yellow("Dry run complete. Add --execute to submit on-chain."));
|
|
1522
|
+
console.log(chalk2.yellow("Dry run complete. Add --execute to submit on-chain, or --write-calls <path> to export for proposals."));
|
|
1022
1523
|
return;
|
|
1023
1524
|
}
|
|
1024
1525
|
const execSpinner = ora2("Executing batch via vault...").start();
|
|
@@ -1049,7 +1550,7 @@ function registerVeniceCommands(program2) {
|
|
|
1049
1550
|
console.log(chalk2.yellow(" Run 'sherwood venice fund' first to distribute sVVV to agents."));
|
|
1050
1551
|
process.exit(1);
|
|
1051
1552
|
}
|
|
1052
|
-
checkSpinner.succeed(`sVVV balance: ${
|
|
1553
|
+
checkSpinner.succeed(`sVVV balance: ${formatUnits2(sVvvBalance, 18)}`);
|
|
1053
1554
|
} catch (err) {
|
|
1054
1555
|
checkSpinner.fail("Failed to check sVVV balance");
|
|
1055
1556
|
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
@@ -1126,17 +1627,17 @@ function registerVeniceCommands(program2) {
|
|
|
1126
1627
|
console.log(chalk2.bold("Venice Inference Status"));
|
|
1127
1628
|
console.log(chalk2.dim("\u2500".repeat(50)));
|
|
1128
1629
|
console.log(chalk2.bold("\n Vault"));
|
|
1129
|
-
console.log(` Profit available: ${
|
|
1130
|
-
console.log(` VVV (unstaked): ${
|
|
1630
|
+
console.log(` Profit available: ${formatUnits2(profit, assetDecimals)} ${assetSymbol}`);
|
|
1631
|
+
console.log(` VVV (unstaked): ${formatUnits2(vaultVvvBalance, 18)}`);
|
|
1131
1632
|
console.log(chalk2.bold("\n Agent sVVV Balances"));
|
|
1132
1633
|
for (const { agent, balance } of agentBalances) {
|
|
1133
1634
|
const isMe = agent.toLowerCase() === account.address.toLowerCase();
|
|
1134
1635
|
const label = isMe ? chalk2.green(`${agent} (you)`) : agent;
|
|
1135
|
-
console.log(` ${label}: ${
|
|
1636
|
+
console.log(` ${label}: ${formatUnits2(balance, 18)} sVVV`);
|
|
1136
1637
|
}
|
|
1137
1638
|
console.log(chalk2.bold("\n Your Wallet"));
|
|
1138
|
-
console.log(` sVVV: ${
|
|
1139
|
-
console.log(` Pending rewards: ${
|
|
1639
|
+
console.log(` sVVV: ${formatUnits2(mySvvv, 18)}`);
|
|
1640
|
+
console.log(` Pending rewards: ${formatUnits2(myPending, 18)} VVV`);
|
|
1140
1641
|
console.log(chalk2.bold("\n Venice API"));
|
|
1141
1642
|
console.log(` Key: ${apiKey ? `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}` : chalk2.dim("not provisioned")}`);
|
|
1142
1643
|
console.log(` Status: ${apiKeyValid ? chalk2.green("valid") : chalk2.red("invalid/missing")}`);
|
|
@@ -1147,16 +1648,79 @@ function registerVeniceCommands(program2) {
|
|
|
1147
1648
|
process.exit(1);
|
|
1148
1649
|
}
|
|
1149
1650
|
});
|
|
1651
|
+
venice.command("models").description("List available Venice inference models").action(async () => {
|
|
1652
|
+
const spinner = ora2("Fetching Venice models...").start();
|
|
1653
|
+
try {
|
|
1654
|
+
const models = await listModels();
|
|
1655
|
+
spinner.succeed(`${models.length} models available`);
|
|
1656
|
+
console.log();
|
|
1657
|
+
for (const model of models) {
|
|
1658
|
+
console.log(` ${model}`);
|
|
1659
|
+
}
|
|
1660
|
+
console.log();
|
|
1661
|
+
} catch (err) {
|
|
1662
|
+
spinner.fail("Failed to list models");
|
|
1663
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1664
|
+
process.exit(1);
|
|
1665
|
+
}
|
|
1666
|
+
});
|
|
1667
|
+
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) => {
|
|
1668
|
+
const messages = [];
|
|
1669
|
+
if (opts.system) {
|
|
1670
|
+
messages.push({ role: "system", content: opts.system });
|
|
1671
|
+
}
|
|
1672
|
+
let userContent = opts.prompt;
|
|
1673
|
+
if (opts.data) {
|
|
1674
|
+
try {
|
|
1675
|
+
const data = readFileSync(opts.data, "utf-8");
|
|
1676
|
+
userContent = `Context data:
|
|
1677
|
+
\`\`\`
|
|
1678
|
+
${data}
|
|
1679
|
+
\`\`\`
|
|
1680
|
+
|
|
1681
|
+
${opts.prompt}`;
|
|
1682
|
+
} catch (err) {
|
|
1683
|
+
console.error(chalk2.red(`Failed to read data file: ${opts.data}`));
|
|
1684
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1685
|
+
process.exit(1);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
messages.push({ role: "user", content: userContent });
|
|
1689
|
+
const spinner = ora2(`Running inference (${opts.model})...`).start();
|
|
1690
|
+
try {
|
|
1691
|
+
const result = await chatCompletion({
|
|
1692
|
+
model: opts.model,
|
|
1693
|
+
messages,
|
|
1694
|
+
temperature: opts.temperature !== void 0 ? Number(opts.temperature) : void 0,
|
|
1695
|
+
maxTokens: opts.maxTokens !== void 0 ? Number(opts.maxTokens) : void 0,
|
|
1696
|
+
enableWebSearch: opts.webSearch,
|
|
1697
|
+
disableThinking: opts.thinking === false
|
|
1698
|
+
});
|
|
1699
|
+
spinner.succeed("Inference complete");
|
|
1700
|
+
if (opts.json) {
|
|
1701
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1702
|
+
} else {
|
|
1703
|
+
console.log();
|
|
1704
|
+
console.log(result.content);
|
|
1705
|
+
console.log();
|
|
1706
|
+
console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
|
|
1707
|
+
}
|
|
1708
|
+
} catch (err) {
|
|
1709
|
+
spinner.fail("Inference failed");
|
|
1710
|
+
console.error(chalk2.red(err instanceof Error ? err.message : String(err)));
|
|
1711
|
+
process.exit(1);
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1150
1714
|
}
|
|
1151
1715
|
|
|
1152
1716
|
// src/commands/allowance.ts
|
|
1153
|
-
import { parseUnits as
|
|
1717
|
+
import { parseUnits as parseUnits6, formatUnits as formatUnits3, isAddress as isAddress3 } from "viem";
|
|
1154
1718
|
import chalk3 from "chalk";
|
|
1155
1719
|
import ora3 from "ora";
|
|
1156
1720
|
|
|
1157
1721
|
// src/strategies/allowance-disburse.ts
|
|
1158
|
-
import { encodeFunctionData as
|
|
1159
|
-
var
|
|
1722
|
+
import { encodeFunctionData as encodeFunctionData7, parseUnits as parseUnits5 } from "viem";
|
|
1723
|
+
var ERC20_ABI3 = [
|
|
1160
1724
|
{
|
|
1161
1725
|
name: "approve",
|
|
1162
1726
|
type: "function",
|
|
@@ -1218,15 +1782,15 @@ var SWAP_ROUTER_EXACT_INPUT_ABI2 = [
|
|
|
1218
1782
|
}
|
|
1219
1783
|
];
|
|
1220
1784
|
function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minUsdc, swapPath) {
|
|
1221
|
-
const assetAmount =
|
|
1785
|
+
const assetAmount = parseUnits5(config.amount, assetDecimals);
|
|
1222
1786
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
1223
1787
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
1224
1788
|
const calls = [];
|
|
1225
1789
|
if (!isUsdc) {
|
|
1226
1790
|
calls.push({
|
|
1227
1791
|
target: assetAddress,
|
|
1228
|
-
data:
|
|
1229
|
-
abi:
|
|
1792
|
+
data: encodeFunctionData7({
|
|
1793
|
+
abi: ERC20_ABI3,
|
|
1230
1794
|
functionName: "approve",
|
|
1231
1795
|
args: [UNISWAP().SWAP_ROUTER, assetAmount]
|
|
1232
1796
|
}),
|
|
@@ -1235,7 +1799,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1235
1799
|
if (isWeth) {
|
|
1236
1800
|
calls.push({
|
|
1237
1801
|
target: UNISWAP().SWAP_ROUTER,
|
|
1238
|
-
data:
|
|
1802
|
+
data: encodeFunctionData7({
|
|
1239
1803
|
abi: SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI2,
|
|
1240
1804
|
functionName: "exactInputSingle",
|
|
1241
1805
|
args: [
|
|
@@ -1255,7 +1819,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1255
1819
|
} else {
|
|
1256
1820
|
calls.push({
|
|
1257
1821
|
target: UNISWAP().SWAP_ROUTER,
|
|
1258
|
-
data:
|
|
1822
|
+
data: encodeFunctionData7({
|
|
1259
1823
|
abi: SWAP_ROUTER_EXACT_INPUT_ABI2,
|
|
1260
1824
|
functionName: "exactInput",
|
|
1261
1825
|
args: [
|
|
@@ -1275,8 +1839,8 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1275
1839
|
for (const agent of agents) {
|
|
1276
1840
|
calls.push({
|
|
1277
1841
|
target: TOKENS().USDC,
|
|
1278
|
-
data:
|
|
1279
|
-
abi:
|
|
1842
|
+
data: encodeFunctionData7({
|
|
1843
|
+
abi: ERC20_ABI3,
|
|
1280
1844
|
functionName: "transfer",
|
|
1281
1845
|
args: [agent, perAgent]
|
|
1282
1846
|
}),
|
|
@@ -1287,7 +1851,7 @@ function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDec
|
|
|
1287
1851
|
}
|
|
1288
1852
|
|
|
1289
1853
|
// src/commands/allowance.ts
|
|
1290
|
-
var
|
|
1854
|
+
var VALID_FEES2 = [500, 3e3, 1e4];
|
|
1291
1855
|
function registerAllowanceCommands(program2) {
|
|
1292
1856
|
const allowance = program2.command("allowance").description("Disburse vault profits to agent wallets");
|
|
1293
1857
|
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 +1861,8 @@ function registerAllowanceCommands(program2) {
|
|
|
1297
1861
|
process.exit(1);
|
|
1298
1862
|
}
|
|
1299
1863
|
const fee = Number(opts.fee);
|
|
1300
|
-
if (!
|
|
1301
|
-
console.error(chalk3.red(`Invalid fee tier. Valid: ${
|
|
1864
|
+
if (!VALID_FEES2.includes(fee)) {
|
|
1865
|
+
console.error(chalk3.red(`Invalid fee tier. Valid: ${VALID_FEES2.join(", ")}`));
|
|
1302
1866
|
process.exit(1);
|
|
1303
1867
|
}
|
|
1304
1868
|
const slippageBps = Number(opts.slippage);
|
|
@@ -1331,7 +1895,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1331
1895
|
console.error(chalk3.red("No agents registered in vault. Register agents first."));
|
|
1332
1896
|
process.exit(1);
|
|
1333
1897
|
}
|
|
1334
|
-
const requestedAmount =
|
|
1898
|
+
const requestedAmount = parseUnits6(opts.amount, assetDecimals);
|
|
1335
1899
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
1336
1900
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
1337
1901
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
@@ -1340,9 +1904,9 @@ function registerAllowanceCommands(program2) {
|
|
|
1340
1904
|
console.log(chalk3.dim("\u2500".repeat(40)));
|
|
1341
1905
|
console.log(` Asset: ${assetSymbol} (${assetDecimals} decimals)`);
|
|
1342
1906
|
console.log(` Amount: ${opts.amount} ${assetSymbol}`);
|
|
1343
|
-
console.log(` Vault balance: ${
|
|
1344
|
-
console.log(` Deposited: ${
|
|
1345
|
-
console.log(` Profit: ${
|
|
1907
|
+
console.log(` Vault balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
1908
|
+
console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
1909
|
+
console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
|
|
1346
1910
|
console.log(` Agents: ${agents.length} (USDC will be split equally)`);
|
|
1347
1911
|
if (!isUsdc) {
|
|
1348
1912
|
console.log(` Routing: ${isWeth ? `WETH \u2192 USDC (fee ${fee})` : `${assetSymbol} \u2192 WETH \u2192 USDC (fee ${fee})`}`);
|
|
@@ -1351,7 +1915,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1351
1915
|
console.log(` Vault: ${vaultAddress}`);
|
|
1352
1916
|
console.log();
|
|
1353
1917
|
if (requestedAmount > profit) {
|
|
1354
|
-
console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${
|
|
1918
|
+
console.warn(chalk3.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits3(profit, assetDecimals)})`));
|
|
1355
1919
|
console.warn(chalk3.yellow(" This will use deposited capital, not just profits."));
|
|
1356
1920
|
console.log();
|
|
1357
1921
|
}
|
|
@@ -1385,7 +1949,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1385
1949
|
}
|
|
1386
1950
|
minUsdc = applySlippage(amountOut, slippageBps);
|
|
1387
1951
|
quoteSpinner.succeed(
|
|
1388
|
-
`Quote: ${
|
|
1952
|
+
`Quote: ${formatUnits3(amountOut, 6)} USDC (min: ${formatUnits3(minUsdc, 6)}, per agent: ${formatUnits3(minUsdc / BigInt(agents.length), 6)})`
|
|
1389
1953
|
);
|
|
1390
1954
|
} catch (err) {
|
|
1391
1955
|
quoteSpinner.fail("Failed to fetch quote");
|
|
@@ -1395,7 +1959,7 @@ function registerAllowanceCommands(program2) {
|
|
|
1395
1959
|
}
|
|
1396
1960
|
const perAgent = minUsdc / BigInt(agents.length);
|
|
1397
1961
|
if (isUsdc) {
|
|
1398
|
-
console.log(chalk3.dim(` Per agent: ${
|
|
1962
|
+
console.log(chalk3.dim(` Per agent: ${formatUnits3(perAgent, 6)} USDC`));
|
|
1399
1963
|
console.log();
|
|
1400
1964
|
}
|
|
1401
1965
|
const config = {
|
|
@@ -1462,14 +2026,14 @@ function registerAllowanceCommands(program2) {
|
|
|
1462
2026
|
console.log(chalk3.dim("\u2500".repeat(50)));
|
|
1463
2027
|
console.log(chalk3.bold("\n Vault"));
|
|
1464
2028
|
console.log(` Asset: ${assetSymbol}`);
|
|
1465
|
-
console.log(` Balance: ${
|
|
1466
|
-
console.log(` Deposited: ${
|
|
1467
|
-
console.log(` Profit: ${
|
|
2029
|
+
console.log(` Balance: ${formatUnits3(assetBalance, assetDecimals)} ${assetSymbol}`);
|
|
2030
|
+
console.log(` Deposited: ${formatUnits3(totalDeposited, assetDecimals)} ${assetSymbol}`);
|
|
2031
|
+
console.log(` Profit: ${formatUnits3(profit, assetDecimals)} ${assetSymbol}`);
|
|
1468
2032
|
console.log(chalk3.bold("\n Agent USDC Balances"));
|
|
1469
2033
|
for (const { agent, balance } of agentBalances) {
|
|
1470
2034
|
const isMe = agent.toLowerCase() === account.address.toLowerCase();
|
|
1471
2035
|
const label = isMe ? chalk3.green(`${agent} (you)`) : agent;
|
|
1472
|
-
console.log(` ${label}: ${
|
|
2036
|
+
console.log(` ${label}: ${formatUnits3(balance, 6)} USDC`);
|
|
1473
2037
|
}
|
|
1474
2038
|
console.log();
|
|
1475
2039
|
} catch (err) {
|
|
@@ -1641,348 +2205,7 @@ function registerIdentityCommands(program2) {
|
|
|
1641
2205
|
import { isAddress as isAddress4 } from "viem";
|
|
1642
2206
|
import chalk5 from "chalk";
|
|
1643
2207
|
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
|
-
}
|
|
2208
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1986
2209
|
|
|
1987
2210
|
// src/lib/format.ts
|
|
1988
2211
|
function formatDurationShort(seconds) {
|
|
@@ -2026,7 +2249,7 @@ function formatTimestamp(ts) {
|
|
|
2026
2249
|
return new Date(Number(ts) * 1e3).toLocaleString();
|
|
2027
2250
|
}
|
|
2028
2251
|
function parseCallsFile(path) {
|
|
2029
|
-
const raw =
|
|
2252
|
+
const raw = readFileSync2(path, "utf-8");
|
|
2030
2253
|
const parsed = JSON.parse(raw);
|
|
2031
2254
|
return parsed.map((c) => ({
|
|
2032
2255
|
target: c.target,
|
|
@@ -2512,7 +2735,7 @@ try {
|
|
|
2512
2735
|
var require2 = createRequire(import.meta.url);
|
|
2513
2736
|
var { version: CLI_VERSION } = require2("../package.json");
|
|
2514
2737
|
async function loadXmtp() {
|
|
2515
|
-
return import("./xmtp-
|
|
2738
|
+
return import("./xmtp-2AHDKL2Q.js");
|
|
2516
2739
|
}
|
|
2517
2740
|
async function loadCron() {
|
|
2518
2741
|
return import("./cron-SKYKVZ6K.js");
|
|
@@ -3189,7 +3412,7 @@ var vaultCmd = program.command("vault");
|
|
|
3189
3412
|
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
3413
|
resolveVault(opts);
|
|
3191
3414
|
const decimals = await getAssetDecimals();
|
|
3192
|
-
const amount =
|
|
3415
|
+
const amount = parseUnits7(opts.amount, decimals);
|
|
3193
3416
|
const spinner = ora7(`Depositing ${opts.amount}...`).start();
|
|
3194
3417
|
try {
|
|
3195
3418
|
const hash = await deposit(amount);
|
|
@@ -3241,81 +3464,8 @@ vaultCmd.command("balance").description("Show LP share balance and asset value")
|
|
|
3241
3464
|
process.exit(1);
|
|
3242
3465
|
}
|
|
3243
3466
|
});
|
|
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
|
-
});
|
|
3467
|
+
var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
|
|
3468
|
+
registerStrategyTemplateCommands(strategy);
|
|
3319
3469
|
program.command("providers").description("List available DeFi providers").action(async () => {
|
|
3320
3470
|
const { MessariProvider, NansenProvider } = await import("./research-IUHVRHR3.js");
|
|
3321
3471
|
const providers = [new MoonwellProvider(), new UniswapProvider(), new MessariProvider(), new NansenProvider()];
|
|
@@ -3328,7 +3478,7 @@ ${info.name} (${info.type})`);
|
|
|
3328
3478
|
}
|
|
3329
3479
|
});
|
|
3330
3480
|
try {
|
|
3331
|
-
const { registerChatCommands } = await import("./chat-
|
|
3481
|
+
const { registerChatCommands } = await import("./chat-XTOTPTGV.js");
|
|
3332
3482
|
registerChatCommands(program);
|
|
3333
3483
|
} catch {
|
|
3334
3484
|
program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
|
|
@@ -3338,14 +3488,14 @@ try {
|
|
|
3338
3488
|
process.exit(1);
|
|
3339
3489
|
});
|
|
3340
3490
|
}
|
|
3341
|
-
var { registerSessionCommands } = await import("./session-
|
|
3491
|
+
var { registerSessionCommands } = await import("./session-RDBY24HJ.js");
|
|
3342
3492
|
registerSessionCommands(program);
|
|
3343
3493
|
registerVeniceCommands(program);
|
|
3344
3494
|
registerAllowanceCommands(program);
|
|
3345
3495
|
registerIdentityCommands(program);
|
|
3346
3496
|
registerProposalCommands(program);
|
|
3347
3497
|
registerGovernorCommands(program);
|
|
3348
|
-
var { registerResearchCommands } = await import("./research-
|
|
3498
|
+
var { registerResearchCommands } = await import("./research-BYQZ2MLK.js");
|
|
3349
3499
|
registerResearchCommands(program);
|
|
3350
3500
|
var configCmd = program.command("config");
|
|
3351
3501
|
configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").option("--rpc <url>", "Custom RPC URL for the active --chain network").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").action((opts) => {
|