@sherwoodagent/cli 0.40.6 → 0.41.4
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/{abis-TXCLIR2K.js → abis-RGCO5GHC.js} +2 -2
- package/dist/{addresses-J4NSZRGB.js → addresses-JBIU5U3T.js} +2 -2
- package/dist/{agent-XBYSALOA.js → agent-LBF6OZRW.js} +3 -3
- package/dist/{chat-EYCDCZUA.js → chat-3GE6474H.js} +6 -6
- package/dist/{chunk-KHTM4GB5.js → chunk-AGKCDHKI.js} +3 -3
- package/dist/{chunk-5OMMVOR6.js → chunk-ARHM3CYN.js} +3 -3
- package/dist/{chunk-FCM6SSL6.js → chunk-CECQNUS6.js} +3 -3
- package/dist/{chunk-W3GXAODE.js → chunk-D77JGXIV.js} +15 -1
- package/dist/chunk-D77JGXIV.js.map +1 -0
- package/dist/{chunk-ITNGXYLB.js → chunk-JGJAKTKK.js} +4 -12
- package/dist/chunk-JGJAKTKK.js.map +1 -0
- package/dist/{chunk-363E34JI.js → chunk-JJ4EF7ZE.js} +3 -3
- package/dist/{chunk-ZN6CUAX7.js → chunk-VMNB4ARO.js} +19 -5
- package/dist/chunk-VMNB4ARO.js.map +1 -0
- package/dist/{eas-MUKSLDIP.js → eas-27JA63VQ.js} +4 -4
- package/dist/{governor-WA74WFOS.js → governor-YLZJIQOB.js} +4 -4
- package/dist/index.js +784 -293
- package/dist/index.js.map +1 -1
- package/dist/{price-ELYQKRSN.js → price-5RAPTAYW.js} +3 -3
- package/dist/{research-HXOXZA4N.js → research-HDEPP2SL.js} +3 -3
- package/dist/{session-NL6KF2Q5.js → session-EST3O7W3.js} +6 -6
- package/dist/{trade-WMPWF6RT.js → trade-XTLUZJB6.js} +7 -7
- package/dist/{xmtp-7CZ5LB5O.js → xmtp-LPCRZRHX.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-ITNGXYLB.js.map +0 -1
- package/dist/chunk-W3GXAODE.js.map +0 -1
- package/dist/chunk-ZN6CUAX7.js.map +0 -1
- /package/dist/{abis-TXCLIR2K.js.map → abis-RGCO5GHC.js.map} +0 -0
- /package/dist/{addresses-J4NSZRGB.js.map → addresses-JBIU5U3T.js.map} +0 -0
- /package/dist/{agent-XBYSALOA.js.map → agent-LBF6OZRW.js.map} +0 -0
- /package/dist/{chat-EYCDCZUA.js.map → chat-3GE6474H.js.map} +0 -0
- /package/dist/{chunk-KHTM4GB5.js.map → chunk-AGKCDHKI.js.map} +0 -0
- /package/dist/{chunk-5OMMVOR6.js.map → chunk-ARHM3CYN.js.map} +0 -0
- /package/dist/{chunk-FCM6SSL6.js.map → chunk-CECQNUS6.js.map} +0 -0
- /package/dist/{chunk-363E34JI.js.map → chunk-JJ4EF7ZE.js.map} +0 -0
- /package/dist/{eas-MUKSLDIP.js.map → eas-27JA63VQ.js.map} +0 -0
- /package/dist/{governor-WA74WFOS.js.map → governor-YLZJIQOB.js.map} +0 -0
- /package/dist/{price-ELYQKRSN.js.map → price-5RAPTAYW.js.map} +0 -0
- /package/dist/{research-HXOXZA4N.js.map → research-HDEPP2SL.js.map} +0 -0
- /package/dist/{session-NL6KF2Q5.js.map → session-EST3O7W3.js.map} +0 -0
- /package/dist/{trade-WMPWF6RT.js.map → trade-XTLUZJB6.js.map} +0 -0
- /package/dist/{xmtp-7CZ5LB5O.js.map → xmtp-LPCRZRHX.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getQuote,
|
|
10
10
|
listModels,
|
|
11
11
|
provisionApiKey
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JGJAKTKK.js";
|
|
13
13
|
import {
|
|
14
14
|
createApproval,
|
|
15
15
|
createJoinRequest,
|
|
@@ -19,14 +19,14 @@ import {
|
|
|
19
19
|
queryJoinRequests,
|
|
20
20
|
revokeAttestation,
|
|
21
21
|
stripReferrerPrefix
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-CECQNUS6.js";
|
|
23
23
|
import {
|
|
24
24
|
createSyndicate,
|
|
25
25
|
getActiveSyndicates,
|
|
26
26
|
getSyndicate,
|
|
27
27
|
subdomainExists,
|
|
28
28
|
updateMetadata
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-AGKCDHKI.js";
|
|
30
30
|
import {
|
|
31
31
|
approveDepositor,
|
|
32
32
|
deposit,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
resolveVaultSyndicate,
|
|
50
50
|
setTextRecord,
|
|
51
51
|
setVaultAddress
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-JJ4EF7ZE.js";
|
|
53
53
|
import {
|
|
54
54
|
PROPOSAL_STATE,
|
|
55
55
|
PROPOSAL_STATES,
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
setVotingPeriod,
|
|
82
82
|
settleProposal,
|
|
83
83
|
vote
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-ARHM3CYN.js";
|
|
85
85
|
import {
|
|
86
86
|
AERODROME,
|
|
87
87
|
AGENT_REGISTRY,
|
|
@@ -94,11 +94,12 @@ import {
|
|
|
94
94
|
TOKENS,
|
|
95
95
|
UNISWAP,
|
|
96
96
|
VENICE
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-VMNB4ARO.js";
|
|
98
98
|
import {
|
|
99
99
|
formatContractError,
|
|
100
100
|
getAccount,
|
|
101
101
|
getPublicClient,
|
|
102
|
+
getWalletClient,
|
|
102
103
|
sendTxWithRetry,
|
|
103
104
|
waitForReceipt,
|
|
104
105
|
writeContractWithRetry
|
|
@@ -144,7 +145,7 @@ import {
|
|
|
144
145
|
SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
|
|
145
146
|
SYNDICATE_VAULT_ABI,
|
|
146
147
|
VENICE_STAKING_ABI
|
|
147
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-D77JGXIV.js";
|
|
148
149
|
import {
|
|
149
150
|
fetchMetadata,
|
|
150
151
|
uploadMetadata
|
|
@@ -154,9 +155,9 @@ import {
|
|
|
154
155
|
import { config as loadDotenv } from "dotenv";
|
|
155
156
|
import { createRequire } from "module";
|
|
156
157
|
import { Command, Option } from "commander";
|
|
157
|
-
import { parseUnits as
|
|
158
|
-
import
|
|
159
|
-
import
|
|
158
|
+
import { parseUnits as parseUnits6, formatUnits as formatUnits5, isAddress as isAddress6 } from "viem";
|
|
159
|
+
import chalk9 from "chalk";
|
|
160
|
+
import ora8 from "ora";
|
|
160
161
|
import { input, confirm, select } from "@inquirer/prompts";
|
|
161
162
|
|
|
162
163
|
// src/providers/moonwell.ts
|
|
@@ -1444,9 +1445,9 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1444
1445
|
console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
|
|
1445
1446
|
process.exit(1);
|
|
1446
1447
|
}
|
|
1447
|
-
const { propose: propose2 } = await import("./governor-
|
|
1448
|
+
const { propose: propose2 } = await import("./governor-YLZJIQOB.js");
|
|
1448
1449
|
const { pinJSON } = await import("./ipfs-IGXLLJCF.js");
|
|
1449
|
-
const { parseDuration: parseDuration2 } = await import("./governor-
|
|
1450
|
+
const { parseDuration: parseDuration2 } = await import("./governor-YLZJIQOB.js");
|
|
1450
1451
|
const performanceFeeBps = BigInt(opts.performanceFee);
|
|
1451
1452
|
if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
|
|
1452
1453
|
console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
|
|
@@ -1553,7 +1554,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1553
1554
|
let prices = [];
|
|
1554
1555
|
let priceSource = null;
|
|
1555
1556
|
try {
|
|
1556
|
-
const { getTokenPricesInAsset } = await import("./price-
|
|
1557
|
+
const { getTokenPricesInAsset } = await import("./price-5RAPTAYW.js");
|
|
1557
1558
|
prices = await getTokenPricesInAsset({
|
|
1558
1559
|
tokens: allocations.map((a, i) => ({
|
|
1559
1560
|
token: a.token,
|
|
@@ -1946,10 +1947,11 @@ async function getActiveSyndicates2(creator) {
|
|
|
1946
1947
|
}
|
|
1947
1948
|
|
|
1948
1949
|
// src/commands/venice.ts
|
|
1949
|
-
import { formatUnits as formatUnits2, isAddress as isAddress2 } from "viem";
|
|
1950
|
+
import { formatUnits as formatUnits2, isAddress as isAddress2, parseUnits as parseUnits2 } from "viem";
|
|
1950
1951
|
import chalk2 from "chalk";
|
|
1951
1952
|
import ora2 from "ora";
|
|
1952
1953
|
import { readFileSync } from "fs";
|
|
1954
|
+
import { createInterface } from "readline/promises";
|
|
1953
1955
|
function registerVeniceCommands(program2) {
|
|
1954
1956
|
const venice = program2.command("venice").description("Venice private inference \u2014 provision API keys, run inference");
|
|
1955
1957
|
venice.command("provision").description("Self-provision a Venice API key (requires sVVV in wallet)").action(async () => {
|
|
@@ -1982,7 +1984,7 @@ function registerVeniceCommands(program2) {
|
|
|
1982
1984
|
console.log(chalk2.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
|
|
1983
1985
|
console.log(chalk2.dim(" Saved to ~/.sherwood/config.json"));
|
|
1984
1986
|
try {
|
|
1985
|
-
const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-
|
|
1987
|
+
const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-27JA63VQ.js");
|
|
1986
1988
|
const { uid } = await createVeniceProvisionAttestation(account.address);
|
|
1987
1989
|
if (uid !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
1988
1990
|
console.log(chalk2.dim(` Attested: ${getEasScanUrl2(uid)}`));
|
|
@@ -1995,6 +1997,203 @@ function registerVeniceCommands(program2) {
|
|
|
1995
1997
|
process.exit(1);
|
|
1996
1998
|
}
|
|
1997
1999
|
});
|
|
2000
|
+
venice.command("stake").description("Stake VVV tokens to receive sVVV (required for API key provisioning)").requiredOption("--amount <n>", "Amount of VVV to stake (human-readable, e.g. 13)").action(async (opts) => {
|
|
2001
|
+
const account = getAccount();
|
|
2002
|
+
const client = getPublicClient();
|
|
2003
|
+
const chain = getChain();
|
|
2004
|
+
const veniceAddrs = VENICE();
|
|
2005
|
+
const amount = parseUnits2(opts.amount, 18);
|
|
2006
|
+
const balSpinner = ora2("Checking VVV balance...").start();
|
|
2007
|
+
try {
|
|
2008
|
+
const vvvBalance = await client.readContract({
|
|
2009
|
+
address: veniceAddrs.VVV,
|
|
2010
|
+
abi: ERC20_ABI,
|
|
2011
|
+
functionName: "balanceOf",
|
|
2012
|
+
args: [account.address]
|
|
2013
|
+
});
|
|
2014
|
+
if (vvvBalance < amount) {
|
|
2015
|
+
balSpinner.fail(`Insufficient VVV: have ${formatUnits2(vvvBalance, 18)}, need ${opts.amount}`);
|
|
2016
|
+
process.exit(1);
|
|
2017
|
+
}
|
|
2018
|
+
balSpinner.succeed(`VVV balance: ${formatUnits2(vvvBalance, 18)}`);
|
|
2019
|
+
} catch (err) {
|
|
2020
|
+
balSpinner.fail("Failed to check VVV balance");
|
|
2021
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2022
|
+
process.exit(1);
|
|
2023
|
+
}
|
|
2024
|
+
const approveSpinner = ora2("Approving VVV for staking contract...").start();
|
|
2025
|
+
try {
|
|
2026
|
+
const approveHash = await writeContractWithRetry({
|
|
2027
|
+
account,
|
|
2028
|
+
chain,
|
|
2029
|
+
address: veniceAddrs.VVV,
|
|
2030
|
+
abi: ERC20_ABI,
|
|
2031
|
+
functionName: "approve",
|
|
2032
|
+
args: [veniceAddrs.STAKING, amount]
|
|
2033
|
+
});
|
|
2034
|
+
await waitForReceipt(approveHash);
|
|
2035
|
+
approveSpinner.succeed("VVV approved");
|
|
2036
|
+
} catch (err) {
|
|
2037
|
+
approveSpinner.fail("Approve failed");
|
|
2038
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2039
|
+
process.exit(1);
|
|
2040
|
+
}
|
|
2041
|
+
const stakeSpinner = ora2(`Staking ${opts.amount} VVV...`).start();
|
|
2042
|
+
try {
|
|
2043
|
+
const stakeHash = await writeContractWithRetry({
|
|
2044
|
+
account,
|
|
2045
|
+
chain,
|
|
2046
|
+
address: veniceAddrs.STAKING,
|
|
2047
|
+
abi: VENICE_STAKING_ABI,
|
|
2048
|
+
functionName: "stake",
|
|
2049
|
+
args: [account.address, amount]
|
|
2050
|
+
});
|
|
2051
|
+
await waitForReceipt(stakeHash);
|
|
2052
|
+
const sVvvBalance = await client.readContract({
|
|
2053
|
+
address: veniceAddrs.STAKING,
|
|
2054
|
+
abi: VENICE_STAKING_ABI,
|
|
2055
|
+
functionName: "balanceOf",
|
|
2056
|
+
args: [account.address]
|
|
2057
|
+
});
|
|
2058
|
+
stakeSpinner.succeed(`Staked ${opts.amount} VVV \u2192 ${formatUnits2(sVvvBalance, 18)} sVVV`);
|
|
2059
|
+
console.log(chalk2.dim(" You can now run: sherwood venice provision"));
|
|
2060
|
+
} catch (err) {
|
|
2061
|
+
stakeSpinner.fail("Stake failed");
|
|
2062
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2063
|
+
process.exit(1);
|
|
2064
|
+
}
|
|
2065
|
+
});
|
|
2066
|
+
venice.command("mint-diem").description("Lock sVVV to mint DIEM (Venice inference credits; ~1d cooldown)").requiredOption("--amount <n>", "Amount of sVVV to lock (human-readable, 18 decimals)").option("--slippage <bps>", "Slippage tolerance in bps (default 500 = 5%)", "500").option("--yes", "Skip the cooldown confirmation prompt").action(async (opts) => {
|
|
2067
|
+
const account = getAccount();
|
|
2068
|
+
const client = getPublicClient();
|
|
2069
|
+
const chain = getChain();
|
|
2070
|
+
const { STAKING, DIEM } = VENICE();
|
|
2071
|
+
const amount = parseUnits2(opts.amount, 18);
|
|
2072
|
+
const slippageBps = BigInt(opts.slippage ?? "500");
|
|
2073
|
+
if (slippageBps < 0n || slippageBps > 10000n) {
|
|
2074
|
+
console.error(chalk2.red(`Invalid slippage bps: ${opts.slippage} (must be 0\u201310000)`));
|
|
2075
|
+
process.exit(1);
|
|
2076
|
+
}
|
|
2077
|
+
const balSpinner = ora2("Checking sVVV balance...").start();
|
|
2078
|
+
let sVvvBalance;
|
|
2079
|
+
try {
|
|
2080
|
+
sVvvBalance = await client.readContract({
|
|
2081
|
+
address: STAKING,
|
|
2082
|
+
abi: VENICE_STAKING_ABI,
|
|
2083
|
+
functionName: "balanceOf",
|
|
2084
|
+
args: [account.address]
|
|
2085
|
+
});
|
|
2086
|
+
} catch (err) {
|
|
2087
|
+
balSpinner.fail("Failed to read sVVV balance");
|
|
2088
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2089
|
+
process.exit(1);
|
|
2090
|
+
}
|
|
2091
|
+
if (sVvvBalance < amount) {
|
|
2092
|
+
balSpinner.fail(
|
|
2093
|
+
`Insufficient sVVV: have ${formatUnits2(sVvvBalance, 18)}, need ${opts.amount}`
|
|
2094
|
+
);
|
|
2095
|
+
console.log(chalk2.yellow(" Stake VVV first (see VeniceInferenceStrategy proposal flow)."));
|
|
2096
|
+
process.exit(1);
|
|
2097
|
+
}
|
|
2098
|
+
balSpinner.succeed(`sVVV balance: ${formatUnits2(sVvvBalance, 18)}`);
|
|
2099
|
+
const quoteSpinner = ora2("Quoting DIEM output...").start();
|
|
2100
|
+
let expected;
|
|
2101
|
+
try {
|
|
2102
|
+
expected = await client.readContract({
|
|
2103
|
+
address: STAKING,
|
|
2104
|
+
abi: VENICE_STAKING_ABI,
|
|
2105
|
+
functionName: "getDiemAmountOut",
|
|
2106
|
+
args: [amount]
|
|
2107
|
+
});
|
|
2108
|
+
} catch (err) {
|
|
2109
|
+
quoteSpinner.fail("Failed to quote DIEM output");
|
|
2110
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2111
|
+
process.exit(1);
|
|
2112
|
+
}
|
|
2113
|
+
if (expected === 0n) {
|
|
2114
|
+
quoteSpinner.fail("Quote returned 0 DIEM \u2014 refusing to mint");
|
|
2115
|
+
process.exit(1);
|
|
2116
|
+
}
|
|
2117
|
+
const minOut = expected * (10000n - slippageBps) / 10000n;
|
|
2118
|
+
quoteSpinner.succeed(
|
|
2119
|
+
`Expected: ${formatUnits2(expected, 18)} DIEM (minOut @ ${slippageBps}bps: ${formatUnits2(minOut, 18)})`
|
|
2120
|
+
);
|
|
2121
|
+
const MIN_SPENDABLE_DIEM = parseUnits2("0.1", 18);
|
|
2122
|
+
let currentDiem = 0n;
|
|
2123
|
+
try {
|
|
2124
|
+
currentDiem = await client.readContract({
|
|
2125
|
+
address: DIEM,
|
|
2126
|
+
abi: ERC20_ABI,
|
|
2127
|
+
functionName: "balanceOf",
|
|
2128
|
+
args: [account.address]
|
|
2129
|
+
});
|
|
2130
|
+
} catch {
|
|
2131
|
+
}
|
|
2132
|
+
const projectedDiem = currentDiem + expected;
|
|
2133
|
+
if (projectedDiem < MIN_SPENDABLE_DIEM) {
|
|
2134
|
+
const shortfall = MIN_SPENDABLE_DIEM - projectedDiem;
|
|
2135
|
+
const sVvvNeeded = (amount * shortfall + expected - 1n) / expected;
|
|
2136
|
+
console.log();
|
|
2137
|
+
console.log(chalk2.red(" \u26A0 Venice requires \u2265 0.1 DIEM minimum before ANY DIEM credit"));
|
|
2138
|
+
console.log(chalk2.red(" becomes spendable on inference calls."));
|
|
2139
|
+
console.log(chalk2.red(` Projected DIEM after mint: ${formatUnits2(projectedDiem, 18)} (short by ${formatUnits2(shortfall, 18)})`));
|
|
2140
|
+
console.log(chalk2.red(` Approx additional sVVV needed: ${formatUnits2(sVvvNeeded, 18)}`));
|
|
2141
|
+
console.log(chalk2.dim(" Below threshold, this DIEM sits idle \u2014 consider acquiring"));
|
|
2142
|
+
console.log(chalk2.dim(" more sVVV first, or use x402 USDC pay-per-request."));
|
|
2143
|
+
}
|
|
2144
|
+
console.log();
|
|
2145
|
+
console.log(chalk2.yellow(" \u26A0 Locked sVVV cannot be unstaked directly. To recover it you must"));
|
|
2146
|
+
console.log(chalk2.yellow(" first call `staking.burnDiem(amount)` (burns DIEM, unlocks sVVV"));
|
|
2147
|
+
console.log(chalk2.yellow(" at your average mint rate), then `initiateUnstake` + wait the"));
|
|
2148
|
+
console.log(chalk2.yellow(" 7-day staking cooldown, then `finalizeUnstake`."));
|
|
2149
|
+
console.log(chalk2.dim(" x402 alternative (pay-per-request in USDC, no DIEM lock):"));
|
|
2150
|
+
console.log(chalk2.dim(" https://docs.venice.ai/overview/guides/generating-api-key-agent#paying-for-inference"));
|
|
2151
|
+
console.log();
|
|
2152
|
+
if (!opts.yes) {
|
|
2153
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2154
|
+
try {
|
|
2155
|
+
const answer = (await rl.question(` Lock ${opts.amount} sVVV for DIEM credits? [y/N] `)).trim().toLowerCase();
|
|
2156
|
+
if (answer !== "y" && answer !== "yes") {
|
|
2157
|
+
console.log(chalk2.dim(" Aborted."));
|
|
2158
|
+
process.exit(0);
|
|
2159
|
+
}
|
|
2160
|
+
} finally {
|
|
2161
|
+
rl.close();
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
const diemBefore = currentDiem;
|
|
2165
|
+
const mintSpinner = ora2(`Minting DIEM from ${opts.amount} sVVV...`).start();
|
|
2166
|
+
try {
|
|
2167
|
+
const hash = await writeContractWithRetry({
|
|
2168
|
+
account,
|
|
2169
|
+
chain,
|
|
2170
|
+
address: STAKING,
|
|
2171
|
+
abi: VENICE_STAKING_ABI,
|
|
2172
|
+
functionName: "mintDiem",
|
|
2173
|
+
args: [amount, minOut]
|
|
2174
|
+
});
|
|
2175
|
+
await waitForReceipt(hash);
|
|
2176
|
+
const diemAfter = await client.readContract({
|
|
2177
|
+
address: DIEM,
|
|
2178
|
+
abi: ERC20_ABI,
|
|
2179
|
+
functionName: "balanceOf",
|
|
2180
|
+
args: [account.address]
|
|
2181
|
+
});
|
|
2182
|
+
const delta = diemAfter - diemBefore;
|
|
2183
|
+
mintSpinner.succeed(
|
|
2184
|
+
`Minted ${formatUnits2(delta > 0n ? delta : diemAfter, 18)} DIEM` + (delta > 0n ? ` (balance: ${formatUnits2(diemAfter, 18)})` : "")
|
|
2185
|
+
);
|
|
2186
|
+
console.log(chalk2.dim(` Tx: ${hash}`));
|
|
2187
|
+
console.log(chalk2.yellow(" Note: Venice requires \u2265 0.1 DIEM to spend ANY DIEM credit, and"));
|
|
2188
|
+
console.log(chalk2.yellow(" refreshes daily allocation at 00:00 UTC. Below threshold,"));
|
|
2189
|
+
console.log(chalk2.yellow(" inference will continue to 402."));
|
|
2190
|
+
console.log(chalk2.dim(' Once over threshold: sherwood venice infer --model <id> --prompt "..."'));
|
|
2191
|
+
} catch (err) {
|
|
2192
|
+
mintSpinner.fail("mintDiem failed");
|
|
2193
|
+
console.error(chalk2.red(formatContractError(err)));
|
|
2194
|
+
process.exit(1);
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
1998
2197
|
venice.command("status").description("Show Venice inference status: sVVV balances, DIEM, API key").requiredOption("--vault <address>", "Vault address").action(async (opts) => {
|
|
1999
2198
|
const vaultAddress = opts.vault;
|
|
2000
2199
|
if (!isAddress2(vaultAddress)) {
|
|
@@ -2032,7 +2231,7 @@ function registerVeniceCommands(program2) {
|
|
|
2032
2231
|
return { agent, balance: bal };
|
|
2033
2232
|
})
|
|
2034
2233
|
);
|
|
2035
|
-
const [mySvvv, myPending] = await Promise.all([
|
|
2234
|
+
const [mySvvv, myPending, myDiem] = await Promise.all([
|
|
2036
2235
|
client.readContract({
|
|
2037
2236
|
address: VENICE().STAKING,
|
|
2038
2237
|
abi: VENICE_STAKING_ABI,
|
|
@@ -2044,6 +2243,12 @@ function registerVeniceCommands(program2) {
|
|
|
2044
2243
|
abi: VENICE_STAKING_ABI,
|
|
2045
2244
|
functionName: "pendingRewards",
|
|
2046
2245
|
args: [account.address]
|
|
2246
|
+
}),
|
|
2247
|
+
client.readContract({
|
|
2248
|
+
address: VENICE().DIEM,
|
|
2249
|
+
abi: ERC20_ABI,
|
|
2250
|
+
functionName: "balanceOf",
|
|
2251
|
+
args: [account.address]
|
|
2047
2252
|
})
|
|
2048
2253
|
]);
|
|
2049
2254
|
const apiKeyValid = await checkApiKeyValid();
|
|
@@ -2065,6 +2270,8 @@ function registerVeniceCommands(program2) {
|
|
|
2065
2270
|
console.log(chalk2.bold("\n Your Wallet"));
|
|
2066
2271
|
console.log(` sVVV: ${formatUnits2(mySvvv, 18)}`);
|
|
2067
2272
|
console.log(` Pending rewards: ${formatUnits2(myPending, 18)} VVV`);
|
|
2273
|
+
console.log(` DIEM (credits): ${formatUnits2(myDiem, 18)}`);
|
|
2274
|
+
console.log(chalk2.dim(" (mint via `sherwood venice mint-diem --amount <sVVV>`)"));
|
|
2068
2275
|
console.log(chalk2.bold("\n Venice API"));
|
|
2069
2276
|
console.log(` Key: ${apiKey ? `${apiKey.slice(0, 8)}...${apiKey.slice(-4)}` : chalk2.dim("not provisioned")}`);
|
|
2070
2277
|
console.log(` Status: ${apiKeyValid ? chalk2.green("valid") : chalk2.red("invalid/missing")}`);
|
|
@@ -2133,7 +2340,7 @@ ${opts.prompt}`;
|
|
|
2133
2340
|
console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
|
|
2134
2341
|
}
|
|
2135
2342
|
try {
|
|
2136
|
-
const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-
|
|
2343
|
+
const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-27JA63VQ.js");
|
|
2137
2344
|
const { keccak256, toHex, isAddress: isAddr } = await import("viem");
|
|
2138
2345
|
const { getChainContracts: getChainContracts2 } = await import("./config-LS7FKZL5.js");
|
|
2139
2346
|
const { getChain: getActiveChain } = await import("./network-KSMKPKNL.js");
|
|
@@ -2160,14 +2367,14 @@ ${opts.prompt}`;
|
|
|
2160
2367
|
}
|
|
2161
2368
|
|
|
2162
2369
|
// src/commands/allowance.ts
|
|
2163
|
-
import { parseUnits as
|
|
2370
|
+
import { parseUnits as parseUnits4, formatUnits as formatUnits3, isAddress as isAddress3 } from "viem";
|
|
2164
2371
|
import chalk3 from "chalk";
|
|
2165
2372
|
import ora3 from "ora";
|
|
2166
2373
|
|
|
2167
2374
|
// src/strategies/allowance-disburse.ts
|
|
2168
|
-
import { encodeFunctionData as encodeFunctionData8, parseUnits as
|
|
2375
|
+
import { encodeFunctionData as encodeFunctionData8, parseUnits as parseUnits3 } from "viem";
|
|
2169
2376
|
function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals, minUsdc, swapPath) {
|
|
2170
|
-
const assetAmount =
|
|
2377
|
+
const assetAmount = parseUnits3(config.amount, assetDecimals);
|
|
2171
2378
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
2172
2379
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
2173
2380
|
const calls = [];
|
|
@@ -2280,7 +2487,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2280
2487
|
console.error(chalk3.red("No agents registered in vault. Register agents first."));
|
|
2281
2488
|
process.exit(1);
|
|
2282
2489
|
}
|
|
2283
|
-
const requestedAmount =
|
|
2490
|
+
const requestedAmount = parseUnits4(opts.amount, assetDecimals);
|
|
2284
2491
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
2285
2492
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
2286
2493
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
@@ -2507,12 +2714,12 @@ function registerIdentityCommands(program2) {
|
|
|
2507
2714
|
identity.command("load").description("Load an existing ERC-8004 agent identity into your config").requiredOption("--id <tokenId>", "Agent token ID to load").action(async (opts) => {
|
|
2508
2715
|
const account = getAccount();
|
|
2509
2716
|
const client = getPublicClient();
|
|
2510
|
-
const
|
|
2717
|
+
const registry2 = AGENT_REGISTRY().IDENTITY_REGISTRY;
|
|
2511
2718
|
const tokenId = Number(opts.id);
|
|
2512
2719
|
const spinner = ora4(`Verifying ownership of agent #${tokenId}...`).start();
|
|
2513
2720
|
try {
|
|
2514
2721
|
const owner = await client.readContract({
|
|
2515
|
-
address:
|
|
2722
|
+
address: registry2,
|
|
2516
2723
|
abi: IDENTITY_REGISTRY_ABI,
|
|
2517
2724
|
functionName: "ownerOf",
|
|
2518
2725
|
args: [BigInt(tokenId)]
|
|
@@ -2533,12 +2740,12 @@ function registerIdentityCommands(program2) {
|
|
|
2533
2740
|
});
|
|
2534
2741
|
identity.command("status").description("Show your agent identity status").action(async () => {
|
|
2535
2742
|
const account = getAccount();
|
|
2536
|
-
const
|
|
2743
|
+
const registry2 = AGENT_REGISTRY().IDENTITY_REGISTRY;
|
|
2537
2744
|
const client = getPublicClient();
|
|
2538
2745
|
const spinner = ora4("Checking identity...").start();
|
|
2539
2746
|
try {
|
|
2540
2747
|
const balance = await client.readContract({
|
|
2541
|
-
address:
|
|
2748
|
+
address: registry2,
|
|
2542
2749
|
abi: IDENTITY_REGISTRY_ABI,
|
|
2543
2750
|
functionName: "balanceOf",
|
|
2544
2751
|
args: [account.address]
|
|
@@ -2549,12 +2756,12 @@ function registerIdentityCommands(program2) {
|
|
|
2549
2756
|
console.log(chalk4.bold("Agent Identity (ERC-8004)"));
|
|
2550
2757
|
console.log(chalk4.dim("\u2500".repeat(40)));
|
|
2551
2758
|
console.log(` Wallet: ${account.address}`);
|
|
2552
|
-
console.log(` Registry: ${
|
|
2759
|
+
console.log(` Registry: ${registry2}`);
|
|
2553
2760
|
console.log(` NFTs owned: ${balance.toString()}`);
|
|
2554
2761
|
if (savedId) {
|
|
2555
2762
|
try {
|
|
2556
2763
|
const owner = await client.readContract({
|
|
2557
|
-
address:
|
|
2764
|
+
address: registry2,
|
|
2558
2765
|
abi: IDENTITY_REGISTRY_ABI,
|
|
2559
2766
|
functionName: "ownerOf",
|
|
2560
2767
|
args: [BigInt(savedId)]
|
|
@@ -3265,7 +3472,7 @@ function printSimulationResult(result, callType) {
|
|
|
3265
3472
|
}
|
|
3266
3473
|
async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
|
|
3267
3474
|
try {
|
|
3268
|
-
const xmtp = await import("./xmtp-
|
|
3475
|
+
const xmtp = await import("./xmtp-LPCRZRHX.js");
|
|
3269
3476
|
const { getAccount: getAccount2 } = await import("./client-HKAG55PQ.js");
|
|
3270
3477
|
const group = await xmtp.getGroup("", subdomain);
|
|
3271
3478
|
const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
|
|
@@ -4074,6 +4281,289 @@ function registerGovernorCommands(program2) {
|
|
|
4074
4281
|
});
|
|
4075
4282
|
}
|
|
4076
4283
|
|
|
4284
|
+
// src/commands/guardian-delegate.ts
|
|
4285
|
+
import chalk8 from "chalk";
|
|
4286
|
+
import ora7 from "ora";
|
|
4287
|
+
import { formatUnits as formatUnits4, isAddress as isAddress5, parseUnits as parseUnits5 } from "viem";
|
|
4288
|
+
var G4 = chalk8.green;
|
|
4289
|
+
var W4 = chalk8.white;
|
|
4290
|
+
var DIM4 = chalk8.gray;
|
|
4291
|
+
var BOLD4 = chalk8.white.bold;
|
|
4292
|
+
var LABEL4 = chalk8.green.bold;
|
|
4293
|
+
var WARN = chalk8.yellow;
|
|
4294
|
+
var SEP4 = () => console.log(DIM4("\u2500".repeat(60)));
|
|
4295
|
+
var GUARDIAN_REGISTRY_ABI = [
|
|
4296
|
+
// Guardian stake
|
|
4297
|
+
{ type: "function", name: "stakeAsGuardian", inputs: [{ type: "uint256" }, { type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
4298
|
+
{ type: "function", name: "requestUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
4299
|
+
{ type: "function", name: "cancelUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
4300
|
+
{ type: "function", name: "claimUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
4301
|
+
// Delegation
|
|
4302
|
+
{ type: "function", name: "delegateStake", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
4303
|
+
{ type: "function", name: "requestUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
4304
|
+
{ type: "function", name: "cancelUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
4305
|
+
{ type: "function", name: "claimUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
4306
|
+
// Commission
|
|
4307
|
+
{ type: "function", name: "setCommission", inputs: [{ type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
4308
|
+
// Views
|
|
4309
|
+
{ type: "function", name: "guardianStake", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
4310
|
+
{ type: "function", name: "isActiveGuardian", inputs: [{ type: "address" }], outputs: [{ type: "bool" }], stateMutability: "view" },
|
|
4311
|
+
{ type: "function", name: "commissionOf", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
4312
|
+
{ type: "function", name: "delegationOf", inputs: [{ type: "address" }, { type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
4313
|
+
{ type: "function", name: "delegatedInbound", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
4314
|
+
// Guardian-fee claim (vault asset)
|
|
4315
|
+
{ type: "function", name: "claimProposalReward", inputs: [{ type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
4316
|
+
{ type: "function", name: "claimDelegatorProposalReward", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [], stateMutability: "nonpayable" }
|
|
4317
|
+
];
|
|
4318
|
+
var ERC20_ABI2 = [
|
|
4319
|
+
{ type: "function", name: "approve", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" },
|
|
4320
|
+
{ type: "function", name: "balanceOf", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
4321
|
+
{ type: "function", name: "decimals", inputs: [], outputs: [{ type: "uint8" }], stateMutability: "view" }
|
|
4322
|
+
];
|
|
4323
|
+
function requireAddress(name, addr) {
|
|
4324
|
+
if (addr === "0x0000000000000000000000000000000000000000") {
|
|
4325
|
+
console.error(chalk8.red(`${name} is not deployed on ${getNetwork()}. Update cli/src/lib/addresses.ts after deploy.`));
|
|
4326
|
+
process.exit(1);
|
|
4327
|
+
}
|
|
4328
|
+
return addr;
|
|
4329
|
+
}
|
|
4330
|
+
function registry() {
|
|
4331
|
+
return requireAddress("GUARDIAN_REGISTRY", SHERWOOD().GUARDIAN_REGISTRY);
|
|
4332
|
+
}
|
|
4333
|
+
function wood() {
|
|
4334
|
+
return requireAddress("WOOD_TOKEN", SHERWOOD().WOOD_TOKEN);
|
|
4335
|
+
}
|
|
4336
|
+
async function ensureWoodAllowance(amount) {
|
|
4337
|
+
const wallet = getWalletClient();
|
|
4338
|
+
const pc = getPublicClient();
|
|
4339
|
+
const addr = wallet.account.address;
|
|
4340
|
+
const current = await pc.readContract({
|
|
4341
|
+
address: wood(),
|
|
4342
|
+
abi: [{ type: "function", name: "allowance", inputs: [{ type: "address" }, { type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" }],
|
|
4343
|
+
functionName: "allowance",
|
|
4344
|
+
args: [addr, registry()]
|
|
4345
|
+
});
|
|
4346
|
+
if (current >= amount) return;
|
|
4347
|
+
const spinner = ora7("Approving WOOD...").start();
|
|
4348
|
+
try {
|
|
4349
|
+
const hash = await wallet.writeContract({
|
|
4350
|
+
address: wood(),
|
|
4351
|
+
abi: ERC20_ABI2,
|
|
4352
|
+
functionName: "approve",
|
|
4353
|
+
args: [registry(), 2n ** 256n - 1n],
|
|
4354
|
+
chain: null,
|
|
4355
|
+
account: wallet.account
|
|
4356
|
+
});
|
|
4357
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4358
|
+
spinner.succeed("WOOD approval granted");
|
|
4359
|
+
} catch (err) {
|
|
4360
|
+
spinner.fail("WOOD approval failed");
|
|
4361
|
+
throw err;
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
function registerGuardianCommands(program2) {
|
|
4365
|
+
const guardian = program2.command("guardian").description("Guardian staking, delegation, and rewards (V1.5)");
|
|
4366
|
+
guardian.command("status [address]").description("Show guardian stake + commission + active status for an address (default: caller)").action(async (addressArg) => {
|
|
4367
|
+
const pc = getPublicClient();
|
|
4368
|
+
let target;
|
|
4369
|
+
if (addressArg) {
|
|
4370
|
+
if (!isAddress5(addressArg)) {
|
|
4371
|
+
console.error(chalk8.red("Invalid address"));
|
|
4372
|
+
process.exit(1);
|
|
4373
|
+
}
|
|
4374
|
+
target = addressArg;
|
|
4375
|
+
} else {
|
|
4376
|
+
const wallet = getWalletClient();
|
|
4377
|
+
target = wallet.account.address;
|
|
4378
|
+
}
|
|
4379
|
+
const spinner = ora7("Loading...").start();
|
|
4380
|
+
try {
|
|
4381
|
+
const [stake, active, commission] = await Promise.all([
|
|
4382
|
+
pc.readContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "guardianStake", args: [target] }),
|
|
4383
|
+
pc.readContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "isActiveGuardian", args: [target] }),
|
|
4384
|
+
pc.readContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "commissionOf", args: [target] })
|
|
4385
|
+
]);
|
|
4386
|
+
const delegatedIn = await pc.readContract({
|
|
4387
|
+
address: registry(),
|
|
4388
|
+
abi: GUARDIAN_REGISTRY_ABI,
|
|
4389
|
+
functionName: "delegatedInbound",
|
|
4390
|
+
args: [target]
|
|
4391
|
+
});
|
|
4392
|
+
spinner.stop();
|
|
4393
|
+
console.log();
|
|
4394
|
+
console.log(LABEL4(" \u25C6 Guardian Status"));
|
|
4395
|
+
SEP4();
|
|
4396
|
+
console.log(W4(` Address: ${G4(target)}`));
|
|
4397
|
+
console.log(W4(` Active guardian: ${active ? G4("yes") : DIM4("no")}`));
|
|
4398
|
+
console.log(W4(` Own stake: ${BOLD4(formatUnits4(stake, 18))} WOOD`));
|
|
4399
|
+
console.log(W4(` Delegated inbound: ${BOLD4(formatUnits4(delegatedIn, 18))} WOOD`));
|
|
4400
|
+
console.log(W4(` Commission: ${BOLD4(`${Number(commission) / 100}%`)}`));
|
|
4401
|
+
SEP4();
|
|
4402
|
+
console.log();
|
|
4403
|
+
} catch (err) {
|
|
4404
|
+
spinner.fail("Failed to load");
|
|
4405
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4406
|
+
process.exit(1);
|
|
4407
|
+
}
|
|
4408
|
+
});
|
|
4409
|
+
guardian.command("stake <amount>").description("Stake as a guardian. Amount in WOOD (min = registry.minGuardianStake).").option("--agent-id <id>", "ERC-8004 agent ID to associate (first-stake only)", "0").action(async (amountStr, opts) => {
|
|
4410
|
+
const amount = parseUnits5(amountStr, 18);
|
|
4411
|
+
const agentId = BigInt(opts.agentId);
|
|
4412
|
+
await ensureWoodAllowance(amount);
|
|
4413
|
+
const wallet = getWalletClient();
|
|
4414
|
+
const pc = getPublicClient();
|
|
4415
|
+
const spinner = ora7(`Staking ${amountStr} WOOD...`).start();
|
|
4416
|
+
try {
|
|
4417
|
+
const hash = await wallet.writeContract({
|
|
4418
|
+
address: registry(),
|
|
4419
|
+
abi: GUARDIAN_REGISTRY_ABI,
|
|
4420
|
+
functionName: "stakeAsGuardian",
|
|
4421
|
+
args: [amount, agentId],
|
|
4422
|
+
chain: null,
|
|
4423
|
+
account: wallet.account
|
|
4424
|
+
});
|
|
4425
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4426
|
+
spinner.succeed(`Staked. Tx: ${hash}`);
|
|
4427
|
+
} catch (err) {
|
|
4428
|
+
spinner.fail("Stake failed");
|
|
4429
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4430
|
+
process.exit(1);
|
|
4431
|
+
}
|
|
4432
|
+
});
|
|
4433
|
+
guardian.command("unstake <action>").description("Unstake flow: 'request' | 'cancel' | 'claim' (7d cooldown)").action(async (action) => {
|
|
4434
|
+
const fn = { request: "requestUnstakeGuardian", cancel: "cancelUnstakeGuardian", claim: "claimUnstakeGuardian" }[action];
|
|
4435
|
+
if (!fn) {
|
|
4436
|
+
console.error(chalk8.red(`Unknown action '${action}'. Use request | cancel | claim.`));
|
|
4437
|
+
process.exit(1);
|
|
4438
|
+
}
|
|
4439
|
+
const wallet = getWalletClient();
|
|
4440
|
+
const pc = getPublicClient();
|
|
4441
|
+
const spinner = ora7(`${action}...`).start();
|
|
4442
|
+
try {
|
|
4443
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: fn, args: [], chain: null, account: wallet.account });
|
|
4444
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4445
|
+
spinner.succeed(`${action} confirmed. Tx: ${hash}`);
|
|
4446
|
+
} catch (err) {
|
|
4447
|
+
spinner.fail(`${action} failed`);
|
|
4448
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4449
|
+
process.exit(1);
|
|
4450
|
+
}
|
|
4451
|
+
});
|
|
4452
|
+
guardian.command("delegate <delegate> <amount>").description("Delegate WOOD stake to a guardian. Amount in WOOD.").action(async (delegate, amountStr) => {
|
|
4453
|
+
if (!isAddress5(delegate)) {
|
|
4454
|
+
console.error(chalk8.red("Invalid delegate address"));
|
|
4455
|
+
process.exit(1);
|
|
4456
|
+
}
|
|
4457
|
+
const amount = parseUnits5(amountStr, 18);
|
|
4458
|
+
await ensureWoodAllowance(amount);
|
|
4459
|
+
const wallet = getWalletClient();
|
|
4460
|
+
const pc = getPublicClient();
|
|
4461
|
+
const spinner = ora7(`Delegating ${amountStr} WOOD to ${delegate}...`).start();
|
|
4462
|
+
try {
|
|
4463
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "delegateStake", args: [delegate, amount], chain: null, account: wallet.account });
|
|
4464
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4465
|
+
spinner.succeed(`Delegated. Tx: ${hash}`);
|
|
4466
|
+
} catch (err) {
|
|
4467
|
+
spinner.fail("Delegation failed");
|
|
4468
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4469
|
+
process.exit(1);
|
|
4470
|
+
}
|
|
4471
|
+
});
|
|
4472
|
+
guardian.command("undelegate <delegate> <action>").description("Unstake-delegation flow: 'request' | 'cancel' | 'claim'").action(async (delegate, action) => {
|
|
4473
|
+
if (!isAddress5(delegate)) {
|
|
4474
|
+
console.error(chalk8.red("Invalid delegate address"));
|
|
4475
|
+
process.exit(1);
|
|
4476
|
+
}
|
|
4477
|
+
const fn = { request: "requestUnstakeDelegation", cancel: "cancelUnstakeDelegation", claim: "claimUnstakeDelegation" }[action];
|
|
4478
|
+
if (!fn) {
|
|
4479
|
+
console.error(chalk8.red(`Unknown action '${action}'. Use request | cancel | claim.`));
|
|
4480
|
+
process.exit(1);
|
|
4481
|
+
}
|
|
4482
|
+
const wallet = getWalletClient();
|
|
4483
|
+
const pc = getPublicClient();
|
|
4484
|
+
const spinner = ora7(`${action}...`).start();
|
|
4485
|
+
try {
|
|
4486
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: fn, args: [delegate], chain: null, account: wallet.account });
|
|
4487
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4488
|
+
spinner.succeed(`${action} confirmed. Tx: ${hash}`);
|
|
4489
|
+
} catch (err) {
|
|
4490
|
+
spinner.fail(`${action} failed`);
|
|
4491
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4492
|
+
process.exit(1);
|
|
4493
|
+
}
|
|
4494
|
+
});
|
|
4495
|
+
guardian.command("set-commission <bps>").description("Set your commission rate in bps (0-5000 = 0-50%). Raises capped cumulatively at 500 bps/epoch.").action(async (bpsStr) => {
|
|
4496
|
+
const bps = BigInt(bpsStr);
|
|
4497
|
+
if (bps > 5000n) {
|
|
4498
|
+
console.error(chalk8.red("Commission cannot exceed 5000 bps (50%)"));
|
|
4499
|
+
process.exit(1);
|
|
4500
|
+
}
|
|
4501
|
+
const wallet = getWalletClient();
|
|
4502
|
+
const pc = getPublicClient();
|
|
4503
|
+
const spinner = ora7(`Setting commission to ${Number(bps) / 100}%...`).start();
|
|
4504
|
+
try {
|
|
4505
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "setCommission", args: [bps], chain: null, account: wallet.account });
|
|
4506
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4507
|
+
spinner.succeed(`Commission set. Tx: ${hash}`);
|
|
4508
|
+
} catch (err) {
|
|
4509
|
+
spinner.fail("setCommission failed");
|
|
4510
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4511
|
+
process.exit(1);
|
|
4512
|
+
}
|
|
4513
|
+
});
|
|
4514
|
+
guardian.command("claim-proposal <proposalId>").description("Claim guardian-fee commission for a settled proposal you voted Approve on (vault asset).").action(async (pidStr) => {
|
|
4515
|
+
const pid = BigInt(pidStr);
|
|
4516
|
+
const wallet = getWalletClient();
|
|
4517
|
+
const pc = getPublicClient();
|
|
4518
|
+
const spinner = ora7("Claiming...").start();
|
|
4519
|
+
try {
|
|
4520
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "claimProposalReward", args: [pid], chain: null, account: wallet.account });
|
|
4521
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4522
|
+
spinner.succeed(`Claimed. Tx: ${hash}`);
|
|
4523
|
+
} catch (err) {
|
|
4524
|
+
spinner.fail("Claim failed");
|
|
4525
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4526
|
+
process.exit(1);
|
|
4527
|
+
}
|
|
4528
|
+
});
|
|
4529
|
+
guardian.command("claim-delegator <delegate> <proposalId>").description("Claim your delegator share of a delegate's guardian-fee pool for a specific proposal.").action(async (delegate, pidStr) => {
|
|
4530
|
+
if (!isAddress5(delegate)) {
|
|
4531
|
+
console.error(chalk8.red("Invalid delegate address"));
|
|
4532
|
+
process.exit(1);
|
|
4533
|
+
}
|
|
4534
|
+
const pid = BigInt(pidStr);
|
|
4535
|
+
const wallet = getWalletClient();
|
|
4536
|
+
const pc = getPublicClient();
|
|
4537
|
+
const spinner = ora7("Claiming delegator share...").start();
|
|
4538
|
+
try {
|
|
4539
|
+
const hash = await wallet.writeContract({ address: registry(), abi: GUARDIAN_REGISTRY_ABI, functionName: "claimDelegatorProposalReward", args: [delegate, pid], chain: null, account: wallet.account });
|
|
4540
|
+
await pc.waitForTransactionReceipt({ hash });
|
|
4541
|
+
spinner.succeed(`Claimed. Tx: ${hash}`);
|
|
4542
|
+
} catch (err) {
|
|
4543
|
+
spinner.fail("Claim failed");
|
|
4544
|
+
console.error(chalk8.red(formatContractError(err)));
|
|
4545
|
+
process.exit(1);
|
|
4546
|
+
}
|
|
4547
|
+
});
|
|
4548
|
+
guardian.command("claim-wood").description("Open merkl.xyz to claim WOOD epoch block-rewards (off-chain distribution).").action(async () => {
|
|
4549
|
+
const wallet = getWalletClient();
|
|
4550
|
+
const addr = wallet.account.address;
|
|
4551
|
+
const url = `https://merkl.angle.money/user/${addr}`;
|
|
4552
|
+
console.log();
|
|
4553
|
+
console.log(LABEL4(" \u25C6 Merkl Reward Claim"));
|
|
4554
|
+
SEP4();
|
|
4555
|
+
console.log(W4(" WOOD epoch block-rewards are distributed off-chain via Merkl."));
|
|
4556
|
+
console.log(W4(" Open this URL in your browser to view + claim pending rewards:"));
|
|
4557
|
+
console.log();
|
|
4558
|
+
console.log(G4(` ${url}`));
|
|
4559
|
+
console.log();
|
|
4560
|
+
console.log(WARN(" Note: guardian-fee rewards (vault assets) are claimed on-chain"));
|
|
4561
|
+
console.log(WARN(" via `sherwood guardian claim-proposal <pid>`."));
|
|
4562
|
+
SEP4();
|
|
4563
|
+
console.log();
|
|
4564
|
+
});
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4077
4567
|
// src/index.ts
|
|
4078
4568
|
try {
|
|
4079
4569
|
loadDotenv();
|
|
@@ -4082,20 +4572,20 @@ try {
|
|
|
4082
4572
|
var require2 = createRequire(import.meta.url);
|
|
4083
4573
|
var { version: CLI_VERSION } = require2("../package.json");
|
|
4084
4574
|
async function loadXmtp() {
|
|
4085
|
-
return import("./xmtp-
|
|
4575
|
+
return import("./xmtp-LPCRZRHX.js");
|
|
4086
4576
|
}
|
|
4087
4577
|
async function loadCron() {
|
|
4088
4578
|
return import("./cron-EOULYO3R.js");
|
|
4089
4579
|
}
|
|
4090
|
-
var
|
|
4091
|
-
var
|
|
4092
|
-
var
|
|
4093
|
-
var
|
|
4094
|
-
var
|
|
4095
|
-
var
|
|
4580
|
+
var G5 = chalk9.green;
|
|
4581
|
+
var W5 = chalk9.white;
|
|
4582
|
+
var DIM5 = chalk9.gray;
|
|
4583
|
+
var BOLD5 = chalk9.white.bold;
|
|
4584
|
+
var LABEL5 = chalk9.green.bold;
|
|
4585
|
+
var SEP5 = () => console.log(DIM5("\u2500".repeat(60)));
|
|
4096
4586
|
function validateAddress(value, name) {
|
|
4097
|
-
if (!
|
|
4098
|
-
console.error(
|
|
4587
|
+
if (!isAddress6(value)) {
|
|
4588
|
+
console.error(chalk9.red(`Invalid ${name} address: ${value}`));
|
|
4099
4589
|
process.exit(1);
|
|
4100
4590
|
}
|
|
4101
4591
|
return value;
|
|
@@ -4115,7 +4605,7 @@ program.name("sherwood").description("CLI for agent-managed investment syndicate
|
|
|
4115
4605
|
process.env.ENABLE_TESTNET = "true";
|
|
4116
4606
|
if (network !== "base") {
|
|
4117
4607
|
console.warn(
|
|
4118
|
-
|
|
4608
|
+
chalk9.yellow("[warn] --testnet ignored, --chain takes precedence")
|
|
4119
4609
|
);
|
|
4120
4610
|
} else {
|
|
4121
4611
|
network = "base-sepolia";
|
|
@@ -4123,39 +4613,39 @@ program.name("sherwood").description("CLI for agent-managed investment syndicate
|
|
|
4123
4613
|
}
|
|
4124
4614
|
setNetwork(network);
|
|
4125
4615
|
if (getNetwork() !== "base") {
|
|
4126
|
-
console.log(
|
|
4616
|
+
console.log(chalk9.yellow(`[${getNetwork()}]`));
|
|
4127
4617
|
}
|
|
4128
4618
|
});
|
|
4129
4619
|
var syndicate = program.command("syndicate");
|
|
4130
4620
|
syndicate.command("create").description("Create a new syndicate via the factory (interactive)").option("--subdomain <name>", "ENS subdomain (skip prompt)").option("--name <name>", "Syndicate name (skip prompt)").option("--agent-id <id>", "ERC-8004 agent identity token ID (skip prompt)").option("--asset <symbol-or-address>", "Vault asset: USDC, WETH, or a token address").option("--description <text>", "Short description").option("--metadata-uri <uri>", "Override metadata URI (skip IPFS upload)").option("--open-deposits", "Allow anyone to deposit (no whitelist)").option("--public-chat", "Enable dashboard spectator mode", false).option("-y, --yes", "Skip confirmation prompt (non-interactive mode)", false).action(async (opts) => {
|
|
4131
4621
|
try {
|
|
4132
4622
|
console.log();
|
|
4133
|
-
console.log(
|
|
4134
|
-
|
|
4623
|
+
console.log(LABEL5(" \u25C6 Create Syndicate"));
|
|
4624
|
+
SEP5();
|
|
4135
4625
|
const wallet = getAccount();
|
|
4136
|
-
console.log(
|
|
4137
|
-
console.log(
|
|
4138
|
-
|
|
4626
|
+
console.log(DIM5(` Wallet: ${wallet.address}`));
|
|
4627
|
+
console.log(DIM5(` Network: ${getChain().name}`));
|
|
4628
|
+
SEP5();
|
|
4139
4629
|
const savedAgentId = getAgentId();
|
|
4140
4630
|
const nonInteractive = opts.yes;
|
|
4141
4631
|
const name = opts.name || (nonInteractive ? (() => {
|
|
4142
4632
|
throw new Error("--name is required in non-interactive mode (-y)");
|
|
4143
4633
|
})() : await input({
|
|
4144
|
-
message:
|
|
4634
|
+
message: G5("Syndicate name"),
|
|
4145
4635
|
validate: (v) => v.length > 0 || "Name is required"
|
|
4146
4636
|
}));
|
|
4147
4637
|
const subdomain = opts.subdomain || (nonInteractive ? name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "") : await input({
|
|
4148
|
-
message:
|
|
4638
|
+
message: G5("ENS subdomain"),
|
|
4149
4639
|
default: name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""),
|
|
4150
4640
|
validate: (v) => v.length >= 3 || "Must be at least 3 characters"
|
|
4151
4641
|
}));
|
|
4152
4642
|
const description = opts.description || (nonInteractive ? `${name} \u2014 a Sherwood syndicate` : await input({
|
|
4153
|
-
message:
|
|
4643
|
+
message: G5("Description"),
|
|
4154
4644
|
default: `${name} \u2014 a Sherwood syndicate`
|
|
4155
4645
|
}));
|
|
4156
|
-
const agentIdStr = opts.agentId || (savedAgentId ? nonInteractive ? String(savedAgentId) : await input({ message:
|
|
4646
|
+
const agentIdStr = opts.agentId || (savedAgentId ? nonInteractive ? String(savedAgentId) : await input({ message: G5("Agent ID (ERC-8004)"), default: String(savedAgentId) }) : nonInteractive ? "0" : await input({ message: G5("Agent ID (ERC-8004)"), validate: (v) => /^\d+$/.test(v) || "Must be a number" }));
|
|
4157
4647
|
const openDeposits = opts.openDeposits !== void 0 ? opts.openDeposits : nonInteractive ? true : await confirm({
|
|
4158
|
-
message:
|
|
4648
|
+
message: G5("Open deposits? (anyone can deposit)"),
|
|
4159
4649
|
default: true
|
|
4160
4650
|
});
|
|
4161
4651
|
const ASSET_SYMBOLS = {
|
|
@@ -4171,14 +4661,14 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4171
4661
|
asset = opts.asset;
|
|
4172
4662
|
} else {
|
|
4173
4663
|
const supported = Object.keys(ASSET_SYMBOLS).join(", ");
|
|
4174
|
-
console.error(
|
|
4664
|
+
console.error(chalk9.red(` Unknown asset "${opts.asset}". Use a symbol (${supported}) or a 0x address.`));
|
|
4175
4665
|
process.exit(1);
|
|
4176
4666
|
}
|
|
4177
4667
|
} else if (nonInteractive) {
|
|
4178
4668
|
asset = TOKENS().USDC !== "0x0000000000000000000000000000000000000000" ? ASSET_SYMBOLS.USDC : ASSET_SYMBOLS.WETH;
|
|
4179
4669
|
} else {
|
|
4180
4670
|
const assetChoice = await select({
|
|
4181
|
-
message:
|
|
4671
|
+
message: G5("Vault asset (what token do depositors provide?)"),
|
|
4182
4672
|
choices: [
|
|
4183
4673
|
{ name: "USDC", value: "USDC", description: "USD Coin (6 decimals)" },
|
|
4184
4674
|
{ name: "WETH", value: "WETH", description: "Wrapped Ether (18 decimals)" }
|
|
@@ -4193,26 +4683,26 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4193
4683
|
]);
|
|
4194
4684
|
const symbol = `sw${assetSymbol}`;
|
|
4195
4685
|
console.log();
|
|
4196
|
-
console.log(
|
|
4197
|
-
|
|
4198
|
-
console.log(
|
|
4199
|
-
console.log(
|
|
4200
|
-
console.log(
|
|
4201
|
-
console.log(
|
|
4202
|
-
console.log(
|
|
4203
|
-
console.log(
|
|
4204
|
-
console.log(
|
|
4205
|
-
|
|
4686
|
+
console.log(LABEL5(" \u25C6 Review"));
|
|
4687
|
+
SEP5();
|
|
4688
|
+
console.log(W5(` Name: ${BOLD5(name)}`));
|
|
4689
|
+
console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
|
|
4690
|
+
console.log(W5(` Description: ${DIM5(description)}`));
|
|
4691
|
+
console.log(W5(` Agent ID: #${agentIdStr}`));
|
|
4692
|
+
console.log(W5(` Asset: ${assetSymbol} (${asset.slice(0, 10)}...)`));
|
|
4693
|
+
console.log(W5(` Share token: ${symbol}`));
|
|
4694
|
+
console.log(W5(` Open deposits: ${openDeposits ? G5("yes") : chalk9.red("no (whitelist)")}`));
|
|
4695
|
+
SEP5();
|
|
4206
4696
|
if (!nonInteractive) {
|
|
4207
|
-
const go = await confirm({ message:
|
|
4697
|
+
const go = await confirm({ message: G5("Deploy syndicate?"), default: true });
|
|
4208
4698
|
if (!go) {
|
|
4209
|
-
console.log(
|
|
4699
|
+
console.log(DIM5(" Cancelled."));
|
|
4210
4700
|
return;
|
|
4211
4701
|
}
|
|
4212
4702
|
}
|
|
4213
4703
|
let metadataURI = opts.metadataUri || "";
|
|
4214
4704
|
if (!metadataURI) {
|
|
4215
|
-
const spinner2 =
|
|
4705
|
+
const spinner2 = ora8({ text: W5("Uploading metadata to IPFS..."), color: "green" }).start();
|
|
4216
4706
|
try {
|
|
4217
4707
|
const metadata = {
|
|
4218
4708
|
schema: "sherwood/syndicate/v1",
|
|
@@ -4226,9 +4716,9 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4226
4716
|
links: {}
|
|
4227
4717
|
};
|
|
4228
4718
|
metadataURI = await uploadMetadata(metadata);
|
|
4229
|
-
spinner2.succeed(
|
|
4719
|
+
spinner2.succeed(G5(`Metadata pinned: ${DIM5(metadataURI)}`));
|
|
4230
4720
|
} catch (err) {
|
|
4231
|
-
spinner2.warn(
|
|
4721
|
+
spinner2.warn(chalk9.yellow(`IPFS upload failed \u2014 using inline metadata`));
|
|
4232
4722
|
const json = JSON.stringify({ name, description, subdomain, asset: assetSymbol, openDeposits, createdBy: "@sherwoodagent/cli" });
|
|
4233
4723
|
metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
|
|
4234
4724
|
}
|
|
@@ -4238,43 +4728,43 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4238
4728
|
const existingInfo = await getSyndicate(existingId);
|
|
4239
4729
|
const callerAddress = getAccount().address.toLowerCase();
|
|
4240
4730
|
if (existingInfo.creator.toLowerCase() !== callerAddress) {
|
|
4241
|
-
console.error(
|
|
4731
|
+
console.error(chalk9.red(`
|
|
4242
4732
|
\u2716 Subdomain '${subdomain}' is already taken by another syndicate.
|
|
4243
4733
|
`));
|
|
4244
4734
|
process.exit(1);
|
|
4245
4735
|
}
|
|
4246
|
-
console.log(
|
|
4736
|
+
console.log(chalk9.yellow(`
|
|
4247
4737
|
\u26A0 Syndicate '${subdomain}' already exists \u2014 resuming setup...
|
|
4248
4738
|
`));
|
|
4249
|
-
const spinner2 =
|
|
4739
|
+
const spinner2 = ora8({ text: W5("Resuming setup..."), color: "green" }).start();
|
|
4250
4740
|
const chainId2 = getChain().id;
|
|
4251
4741
|
setChainContract(chainId2, "vault", existingInfo.vault);
|
|
4252
4742
|
addSyndicate(chainId2, { subdomain, vault: existingInfo.vault, role: "creator" });
|
|
4253
4743
|
setPrimarySyndicate(chainId2, subdomain);
|
|
4254
|
-
spinner2.text =
|
|
4744
|
+
spinner2.text = W5("Checking agent registration...");
|
|
4255
4745
|
try {
|
|
4256
4746
|
setVaultAddress(existingInfo.vault);
|
|
4257
4747
|
const isAlreadyAgent = await isAgent(getAccount().address);
|
|
4258
4748
|
if (!isAlreadyAgent) {
|
|
4259
|
-
spinner2.text =
|
|
4749
|
+
spinner2.text = W5("Registering creator as agent...");
|
|
4260
4750
|
await registerAgent(BigInt(agentIdStr), getAccount().address);
|
|
4261
4751
|
}
|
|
4262
4752
|
} catch {
|
|
4263
4753
|
}
|
|
4264
|
-
spinner2.text =
|
|
4754
|
+
spinner2.text = W5("Checking chat group...");
|
|
4265
4755
|
try {
|
|
4266
4756
|
const xmtp = await loadXmtp();
|
|
4267
4757
|
const xmtpClient = await xmtp.getXmtpClient();
|
|
4268
4758
|
try {
|
|
4269
4759
|
await xmtp.getGroup(xmtpClient, subdomain);
|
|
4270
4760
|
} catch {
|
|
4271
|
-
spinner2.text =
|
|
4761
|
+
spinner2.text = W5("Creating chat group...");
|
|
4272
4762
|
const groupId = await xmtp.createSyndicateGroup(xmtpClient, subdomain, opts.publicChat);
|
|
4273
4763
|
await setTextRecord(subdomain, "xmtpGroupId", groupId, existingInfo.vault);
|
|
4274
4764
|
cacheGroupId(subdomain, groupId);
|
|
4275
4765
|
}
|
|
4276
4766
|
} catch {
|
|
4277
|
-
console.warn(
|
|
4767
|
+
console.warn(chalk9.yellow("\n \u26A0 Could not set up XMTP chat group"));
|
|
4278
4768
|
}
|
|
4279
4769
|
try {
|
|
4280
4770
|
const cron = await loadCron();
|
|
@@ -4283,20 +4773,20 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4283
4773
|
}
|
|
4284
4774
|
spinner2.stop();
|
|
4285
4775
|
console.log();
|
|
4286
|
-
console.log(
|
|
4287
|
-
|
|
4288
|
-
console.log(
|
|
4289
|
-
console.log(
|
|
4290
|
-
console.log(
|
|
4291
|
-
console.log(
|
|
4776
|
+
console.log(LABEL5(" \u25C6 Syndicate Setup Resumed"));
|
|
4777
|
+
SEP5();
|
|
4778
|
+
console.log(W5(` ID: ${G5(`#${existingId}`)}`));
|
|
4779
|
+
console.log(W5(` Vault: ${G5(existingInfo.vault)}`));
|
|
4780
|
+
console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
|
|
4781
|
+
console.log(W5(` Chat: ${DIM5(`sherwood chat ${subdomain}`)}`));
|
|
4292
4782
|
const refParam2 = getAgentId() ? `?ref=${getAgentId()}` : "";
|
|
4293
|
-
console.log(
|
|
4294
|
-
|
|
4295
|
-
console.log(
|
|
4783
|
+
console.log(W5(` Share: ${G5(`https://sherwood.sh/syndicate/${subdomain}${refParam2}`)}`));
|
|
4784
|
+
SEP5();
|
|
4785
|
+
console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
|
|
4296
4786
|
console.log();
|
|
4297
4787
|
return;
|
|
4298
4788
|
}
|
|
4299
|
-
const spinner =
|
|
4789
|
+
const spinner = ora8({ text: W5("Deploying vault via factory..."), color: "green" }).start();
|
|
4300
4790
|
const result = await createSyndicate({
|
|
4301
4791
|
creatorAgentId: BigInt(agentIdStr),
|
|
4302
4792
|
metadataURI,
|
|
@@ -4311,7 +4801,7 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4311
4801
|
addSyndicate(chainId, { subdomain, vault: result.vault, role: "creator" });
|
|
4312
4802
|
setPrimarySyndicate(chainId, subdomain);
|
|
4313
4803
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
4314
|
-
spinner.text =
|
|
4804
|
+
spinner.text = W5("Registering creator as agent...");
|
|
4315
4805
|
try {
|
|
4316
4806
|
setVaultAddress(result.vault);
|
|
4317
4807
|
const creatorAddress = getAccount().address;
|
|
@@ -4321,9 +4811,9 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4321
4811
|
// agentAddress = creator EOA (direct execution)
|
|
4322
4812
|
);
|
|
4323
4813
|
} catch (regErr) {
|
|
4324
|
-
console.warn(
|
|
4814
|
+
console.warn(chalk9.yellow("\n \u26A0 Could not auto-register creator as agent \u2014 register manually with `syndicate add`"));
|
|
4325
4815
|
}
|
|
4326
|
-
spinner.text =
|
|
4816
|
+
spinner.text = W5("Setting up chat...");
|
|
4327
4817
|
try {
|
|
4328
4818
|
const xmtp = await loadXmtp();
|
|
4329
4819
|
const xmtpClient = await xmtp.getXmtpClient();
|
|
@@ -4334,42 +4824,42 @@ syndicate.command("create").description("Create a new syndicate via the factory
|
|
|
4334
4824
|
} catch {
|
|
4335
4825
|
}
|
|
4336
4826
|
} catch {
|
|
4337
|
-
console.warn(
|
|
4338
|
-
console.warn(
|
|
4827
|
+
console.warn(chalk9.yellow("\n \u26A0 Could not create XMTP chat group"));
|
|
4828
|
+
console.warn(chalk9.dim(` Recover later with: sherwood chat ${subdomain} init`));
|
|
4339
4829
|
}
|
|
4340
4830
|
try {
|
|
4341
4831
|
const cron = await loadCron();
|
|
4342
4832
|
const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
|
|
4343
4833
|
if (cronResult.isOpenClaw && cronResult.registered) {
|
|
4344
|
-
console.log(
|
|
4834
|
+
console.log(G5(" \u2713 Participation crons registered (15m check + hourly summary)"));
|
|
4345
4835
|
} else if (!cronResult.isOpenClaw) {
|
|
4346
|
-
console.log(
|
|
4836
|
+
console.log(DIM5(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
|
|
4347
4837
|
}
|
|
4348
4838
|
} catch {
|
|
4349
4839
|
}
|
|
4350
4840
|
spinner.stop();
|
|
4351
4841
|
console.log();
|
|
4352
|
-
console.log(
|
|
4353
|
-
|
|
4354
|
-
console.log(
|
|
4355
|
-
console.log(
|
|
4356
|
-
console.log(
|
|
4357
|
-
console.log(
|
|
4358
|
-
console.log(
|
|
4359
|
-
console.log(
|
|
4842
|
+
console.log(LABEL5(" \u25C6 Syndicate Created"));
|
|
4843
|
+
SEP5();
|
|
4844
|
+
console.log(W5(` ID: ${G5(`#${result.syndicateId}`)}`));
|
|
4845
|
+
console.log(W5(` Vault: ${G5(result.vault)}`));
|
|
4846
|
+
console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
|
|
4847
|
+
console.log(W5(` Metadata: ${DIM5(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
|
|
4848
|
+
console.log(W5(` Explorer: ${DIM5(getExplorerUrl(result.hash))}`));
|
|
4849
|
+
console.log(W5(` Chat: ${DIM5(`sherwood chat ${subdomain}`)}`));
|
|
4360
4850
|
const refParam = getAgentId() ? `?ref=${getAgentId()}` : "";
|
|
4361
|
-
console.log(
|
|
4362
|
-
|
|
4363
|
-
console.log(
|
|
4851
|
+
console.log(W5(` Share: ${G5(`https://sherwood.sh/syndicate/${subdomain}${refParam}`)}`));
|
|
4852
|
+
SEP5();
|
|
4853
|
+
console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
|
|
4364
4854
|
console.log();
|
|
4365
4855
|
} catch (err) {
|
|
4366
|
-
console.error(
|
|
4856
|
+
console.error(chalk9.red(`
|
|
4367
4857
|
\u2716 ${formatContractError(err)}`));
|
|
4368
4858
|
process.exit(1);
|
|
4369
4859
|
}
|
|
4370
4860
|
});
|
|
4371
4861
|
syndicate.command("list").description("List active syndicates (queries subgraph, falls back to on-chain)").option("--creator <address>", "Filter by creator address").action(async (opts) => {
|
|
4372
|
-
const spinner =
|
|
4862
|
+
const spinner = ora8("Loading syndicates...").start();
|
|
4373
4863
|
try {
|
|
4374
4864
|
let syndicates;
|
|
4375
4865
|
if (process.env.SUBGRAPH_URL) {
|
|
@@ -4388,39 +4878,39 @@ syndicate.command("list").description("List active syndicates (queries subgraph,
|
|
|
4388
4878
|
}
|
|
4389
4879
|
spinner.stop();
|
|
4390
4880
|
if (syndicates.length === 0) {
|
|
4391
|
-
console.log(
|
|
4881
|
+
console.log(chalk9.dim("No active syndicates found."));
|
|
4392
4882
|
return;
|
|
4393
4883
|
}
|
|
4394
4884
|
console.log();
|
|
4395
|
-
console.log(
|
|
4885
|
+
console.log(chalk9.bold(`Active Syndicates (${syndicates.length})`));
|
|
4396
4886
|
if (!process.env.SUBGRAPH_URL) {
|
|
4397
|
-
console.log(
|
|
4887
|
+
console.log(chalk9.dim(" (Set SUBGRAPH_URL for faster indexed queries)"));
|
|
4398
4888
|
}
|
|
4399
|
-
console.log(
|
|
4889
|
+
console.log(chalk9.dim("\u2500".repeat(70)));
|
|
4400
4890
|
for (const s of syndicates) {
|
|
4401
4891
|
const ts = typeof s.createdAt === "string" ? Number(s.createdAt) : Number(s.createdAt);
|
|
4402
4892
|
const date = new Date(ts * 1e3).toLocaleDateString();
|
|
4403
4893
|
const ensName = s.subdomain ? `${s.subdomain}.sherwoodagent.eth` : "";
|
|
4404
|
-
console.log(` #${s.id} ${
|
|
4405
|
-
if (ensName) console.log(` Vault: ${
|
|
4894
|
+
console.log(` #${s.id} ${chalk9.bold(ensName || String(s.vault))}`);
|
|
4895
|
+
if (ensName) console.log(` Vault: ${chalk9.cyan(String(s.vault))}`);
|
|
4406
4896
|
console.log(` Creator: ${s.creator}`);
|
|
4407
4897
|
console.log(` Created: ${date}`);
|
|
4408
4898
|
if (s.totalDeposits) {
|
|
4409
4899
|
console.log(` Deposits: ${s.totalDeposits} USDC`);
|
|
4410
4900
|
}
|
|
4411
4901
|
if (s.metadataURI) {
|
|
4412
|
-
console.log(` Metadata: ${
|
|
4902
|
+
console.log(` Metadata: ${chalk9.dim(s.metadataURI)}`);
|
|
4413
4903
|
}
|
|
4414
4904
|
console.log();
|
|
4415
4905
|
}
|
|
4416
4906
|
} catch (err) {
|
|
4417
4907
|
spinner.fail("Failed to load syndicates");
|
|
4418
|
-
console.error(
|
|
4908
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4419
4909
|
process.exit(1);
|
|
4420
4910
|
}
|
|
4421
4911
|
});
|
|
4422
4912
|
syndicate.command("info").description("Display syndicate details by ID or subdomain").argument("<id>", "Syndicate ID or subdomain name").action(async (idStr) => {
|
|
4423
|
-
const spinner =
|
|
4913
|
+
const spinner = ora8("Loading syndicate info...").start();
|
|
4424
4914
|
try {
|
|
4425
4915
|
let id;
|
|
4426
4916
|
if (/^\d+$/.test(idStr)) {
|
|
@@ -4432,33 +4922,33 @@ syndicate.command("info").description("Display syndicate details by ID or subdom
|
|
|
4432
4922
|
const info = await getSyndicate(id);
|
|
4433
4923
|
spinner.stop();
|
|
4434
4924
|
if (!info.vault || info.vault === "0x0000000000000000000000000000000000000000") {
|
|
4435
|
-
console.log(
|
|
4925
|
+
console.log(chalk9.red(`Syndicate #${id} not found.`));
|
|
4436
4926
|
process.exit(1);
|
|
4437
4927
|
}
|
|
4438
4928
|
const date = new Date(Number(info.createdAt) * 1e3).toLocaleDateString();
|
|
4439
4929
|
console.log();
|
|
4440
|
-
console.log(
|
|
4441
|
-
console.log(
|
|
4930
|
+
console.log(chalk9.bold(`Syndicate #${info.id}`));
|
|
4931
|
+
console.log(chalk9.dim("\u2500".repeat(40)));
|
|
4442
4932
|
if (info.subdomain) {
|
|
4443
|
-
console.log(` ENS: ${
|
|
4933
|
+
console.log(` ENS: ${chalk9.bold(`${info.subdomain}.sherwoodagent.eth`)}`);
|
|
4444
4934
|
}
|
|
4445
|
-
console.log(` Vault: ${
|
|
4935
|
+
console.log(` Vault: ${chalk9.cyan(info.vault)}`);
|
|
4446
4936
|
console.log(` Creator: ${info.creator}`);
|
|
4447
4937
|
console.log(` Created: ${date}`);
|
|
4448
|
-
console.log(` Active: ${info.active ?
|
|
4938
|
+
console.log(` Active: ${info.active ? chalk9.green("yes") : chalk9.red("no")}`);
|
|
4449
4939
|
if (info.metadataURI) {
|
|
4450
|
-
console.log(` Metadata: ${
|
|
4940
|
+
console.log(` Metadata: ${chalk9.dim(info.metadataURI)}`);
|
|
4451
4941
|
}
|
|
4452
4942
|
if (info.subdomain) {
|
|
4453
4943
|
const xmtpGroupId = getCachedGroupId(info.subdomain);
|
|
4454
4944
|
if (xmtpGroupId) {
|
|
4455
|
-
console.log(` XMTP Group: ${
|
|
4945
|
+
console.log(` XMTP Group: ${chalk9.cyan(xmtpGroupId)}`);
|
|
4456
4946
|
}
|
|
4457
4947
|
}
|
|
4458
4948
|
setVaultAddress(info.vault);
|
|
4459
4949
|
const vaultInfo = await getVaultInfo();
|
|
4460
4950
|
console.log();
|
|
4461
|
-
console.log(
|
|
4951
|
+
console.log(chalk9.bold(" Vault Stats"));
|
|
4462
4952
|
console.log(` Total Assets: ${vaultInfo.totalAssets}`);
|
|
4463
4953
|
console.log(` Agent Count: ${vaultInfo.agentCount}`);
|
|
4464
4954
|
console.log(` Redemptions Locked: ${vaultInfo.redemptionsLocked}`);
|
|
@@ -4466,12 +4956,12 @@ syndicate.command("info").description("Display syndicate details by ID or subdom
|
|
|
4466
4956
|
console.log();
|
|
4467
4957
|
} catch (err) {
|
|
4468
4958
|
spinner.fail("Failed to load syndicate info");
|
|
4469
|
-
console.error(
|
|
4959
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4470
4960
|
process.exit(1);
|
|
4471
4961
|
}
|
|
4472
4962
|
});
|
|
4473
4963
|
syndicate.command("update-metadata").description("Update syndicate metadata (creator only)").requiredOption("--id <id>", "Syndicate ID").option("--name <name>", "Syndicate name").option("--description <text>", "Short description").option("--uri <uri>", "Direct metadata URI (skips IPFS upload)").action(async (opts) => {
|
|
4474
|
-
const spinner =
|
|
4964
|
+
const spinner = ora8({ text: W5("Loading syndicate..."), color: "green" }).start();
|
|
4475
4965
|
try {
|
|
4476
4966
|
const syndicateId = BigInt(opts.id);
|
|
4477
4967
|
let metadataURI = opts.uri;
|
|
@@ -4483,7 +4973,7 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
|
|
|
4483
4973
|
}
|
|
4484
4974
|
const name = opts.name || info.subdomain;
|
|
4485
4975
|
const description = opts.description || `${name} \u2014 a Sherwood syndicate on ${info.subdomain}.sherwoodagent.eth`;
|
|
4486
|
-
spinner.text =
|
|
4976
|
+
spinner.text = W5("Uploading metadata to IPFS...");
|
|
4487
4977
|
const metadata = {
|
|
4488
4978
|
schema: "sherwood/syndicate/v1",
|
|
4489
4979
|
name,
|
|
@@ -4494,48 +4984,48 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
|
|
|
4494
4984
|
links: {}
|
|
4495
4985
|
};
|
|
4496
4986
|
metadataURI = await uploadMetadata(metadata);
|
|
4497
|
-
spinner.text =
|
|
4987
|
+
spinner.text = W5("Updating on-chain metadata...");
|
|
4498
4988
|
}
|
|
4499
4989
|
const hash = await updateMetadata(syndicateId, metadataURI);
|
|
4500
|
-
spinner.succeed(
|
|
4501
|
-
console.log(
|
|
4502
|
-
console.log(
|
|
4990
|
+
spinner.succeed(G5(`Metadata updated`));
|
|
4991
|
+
console.log(DIM5(` IPFS: ${metadataURI}`));
|
|
4992
|
+
console.log(DIM5(` ${getExplorerUrl(hash)}`));
|
|
4503
4993
|
} catch (err) {
|
|
4504
4994
|
spinner.fail("Metadata update failed");
|
|
4505
|
-
console.error(
|
|
4995
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4506
4996
|
process.exit(1);
|
|
4507
4997
|
}
|
|
4508
4998
|
});
|
|
4509
4999
|
syndicate.command("approve-depositor").description("Approve an address to deposit (owner only)").option("--vault <address>", "Vault address (default: from config)").requiredOption("--depositor <address>", "Address to approve").action(async (opts) => {
|
|
4510
5000
|
resolveVault(opts);
|
|
4511
|
-
const spinner =
|
|
5001
|
+
const spinner = ora8("Approving depositor...").start();
|
|
4512
5002
|
try {
|
|
4513
5003
|
const depositor = validateAddress(opts.depositor, "depositor");
|
|
4514
5004
|
const hash = await approveDepositor(depositor);
|
|
4515
5005
|
spinner.succeed(`Depositor approved: ${hash}`);
|
|
4516
|
-
console.log(
|
|
5006
|
+
console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
|
|
4517
5007
|
} catch (err) {
|
|
4518
5008
|
spinner.fail("Approval failed");
|
|
4519
|
-
console.error(
|
|
5009
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4520
5010
|
process.exit(1);
|
|
4521
5011
|
}
|
|
4522
5012
|
});
|
|
4523
5013
|
syndicate.command("remove-depositor").description("Remove an address from the depositor whitelist (owner only)").option("--vault <address>", "Vault address (default: from config)").requiredOption("--depositor <address>", "Address to remove").action(async (opts) => {
|
|
4524
5014
|
resolveVault(opts);
|
|
4525
|
-
const spinner =
|
|
5015
|
+
const spinner = ora8("Removing depositor...").start();
|
|
4526
5016
|
try {
|
|
4527
5017
|
const depositor = validateAddress(opts.depositor, "depositor");
|
|
4528
5018
|
const hash = await removeDepositor(depositor);
|
|
4529
5019
|
spinner.succeed(`Depositor removed: ${hash}`);
|
|
4530
|
-
console.log(
|
|
5020
|
+
console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
|
|
4531
5021
|
} catch (err) {
|
|
4532
5022
|
spinner.fail("Removal failed");
|
|
4533
|
-
console.error(
|
|
5023
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4534
5024
|
process.exit(1);
|
|
4535
5025
|
}
|
|
4536
5026
|
});
|
|
4537
5027
|
syndicate.command("add").description("Register an agent on a syndicate vault (creator only)").option("--vault <address>", "Vault address (default: from config)").option("--agent-id <id>", "Agent's ERC-8004 identity token ID (resolved from wallet if omitted)").requiredOption("--wallet <address>", "Agent wallet address").action(async (opts) => {
|
|
4538
|
-
const spinner =
|
|
5028
|
+
const spinner = ora8("Verifying creator...").start();
|
|
4539
5029
|
try {
|
|
4540
5030
|
resolveVault(opts);
|
|
4541
5031
|
const vaultAddress = getVaultAddress();
|
|
@@ -4550,15 +5040,15 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
|
|
|
4550
5040
|
if (opts.agentId) {
|
|
4551
5041
|
agentId = BigInt(opts.agentId);
|
|
4552
5042
|
} else {
|
|
4553
|
-
const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-
|
|
4554
|
-
const
|
|
4555
|
-
if (
|
|
5043
|
+
const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-JBIU5U3T.js");
|
|
5044
|
+
const registry2 = AGENT_REGISTRY2().IDENTITY_REGISTRY;
|
|
5045
|
+
if (registry2 === "0x0000000000000000000000000000000000000000") {
|
|
4556
5046
|
agentId = 0n;
|
|
4557
5047
|
} else {
|
|
4558
5048
|
spinner.text = "Looking up ERC-8004 identity from wallet...";
|
|
4559
5049
|
const client = getPublicClient();
|
|
4560
5050
|
const balance = await client.readContract({
|
|
4561
|
-
address:
|
|
5051
|
+
address: registry2,
|
|
4562
5052
|
abi: [{
|
|
4563
5053
|
name: "balanceOf",
|
|
4564
5054
|
type: "function",
|
|
@@ -4571,11 +5061,11 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
|
|
|
4571
5061
|
});
|
|
4572
5062
|
if (balance === 0n) {
|
|
4573
5063
|
spinner.fail("Agent wallet does not own an ERC-8004 identity NFT");
|
|
4574
|
-
console.error(
|
|
5064
|
+
console.error(chalk9.dim(" Mint one first: sherwood identity mint --name <name>"));
|
|
4575
5065
|
process.exit(1);
|
|
4576
5066
|
}
|
|
4577
5067
|
const tokenId = await client.readContract({
|
|
4578
|
-
address:
|
|
5068
|
+
address: registry2,
|
|
4579
5069
|
abi: [{
|
|
4580
5070
|
name: "tokenOfOwnerByIndex",
|
|
4581
5071
|
type: "function",
|
|
@@ -4587,13 +5077,13 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
|
|
|
4587
5077
|
args: [agentWallet, 0n]
|
|
4588
5078
|
});
|
|
4589
5079
|
agentId = tokenId;
|
|
4590
|
-
console.log(
|
|
5080
|
+
console.log(chalk9.dim(` Resolved agent ID: #${agentId}`));
|
|
4591
5081
|
}
|
|
4592
5082
|
}
|
|
4593
5083
|
spinner.text = "Registering agent...";
|
|
4594
5084
|
const hash = await registerAgent(agentId, agentWallet);
|
|
4595
5085
|
spinner.succeed(`Agent registered: ${hash}`);
|
|
4596
|
-
console.log(
|
|
5086
|
+
console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
|
|
4597
5087
|
try {
|
|
4598
5088
|
const xmtp = await loadXmtp();
|
|
4599
5089
|
const xmtpClient = await xmtp.getXmtpClient();
|
|
@@ -4605,14 +5095,14 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
|
|
|
4605
5095
|
syndicate: subdomain,
|
|
4606
5096
|
timestamp: Math.floor(Date.now() / 1e3)
|
|
4607
5097
|
});
|
|
4608
|
-
console.log(
|
|
5098
|
+
console.log(chalk9.dim(` Added to chat: ${subdomain}`));
|
|
4609
5099
|
} catch {
|
|
4610
|
-
console.warn(
|
|
4611
|
-
console.warn(
|
|
5100
|
+
console.warn(chalk9.yellow(" \u26A0 Could not add agent to chat group"));
|
|
5101
|
+
console.warn(chalk9.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
|
|
4612
5102
|
}
|
|
4613
5103
|
} catch (err) {
|
|
4614
5104
|
spinner.fail("Registration failed");
|
|
4615
|
-
console.error(
|
|
5105
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4616
5106
|
process.exit(1);
|
|
4617
5107
|
}
|
|
4618
5108
|
});
|
|
@@ -4620,7 +5110,7 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
|
|
|
4620
5110
|
try {
|
|
4621
5111
|
const subdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
|
|
4622
5112
|
if (!subdomain) {
|
|
4623
|
-
console.error(
|
|
5113
|
+
console.error(chalk9.red(" No syndicate configured. Pass --subdomain <name> or run 'syndicate create/join' first."));
|
|
4624
5114
|
process.exit(1);
|
|
4625
5115
|
}
|
|
4626
5116
|
const syndicateInfo = await resolveSyndicate(subdomain);
|
|
@@ -4628,13 +5118,13 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
|
|
|
4628
5118
|
const refParam = agentId ? `?ref=${agentId}` : "";
|
|
4629
5119
|
const dashboardUrl = `https://sherwood.sh/syndicate/${subdomain}${refParam}`;
|
|
4630
5120
|
console.log();
|
|
4631
|
-
console.log(
|
|
4632
|
-
|
|
4633
|
-
console.log(
|
|
4634
|
-
console.log(
|
|
4635
|
-
console.log(
|
|
4636
|
-
console.log(
|
|
4637
|
-
|
|
5121
|
+
console.log(LABEL5(" \u25C6 Share Your Syndicate"));
|
|
5122
|
+
SEP5();
|
|
5123
|
+
console.log(W5(` Dashboard: ${G5(dashboardUrl)}`));
|
|
5124
|
+
console.log(W5(` ENS: ${DIM5(`${subdomain}.sherwoodagent.eth`)}`));
|
|
5125
|
+
console.log(W5(` Vault: ${DIM5(syndicateInfo.vault)}`));
|
|
5126
|
+
console.log(W5(` Join CLI: ${DIM5(`sherwood syndicate join --subdomain ${subdomain}`)}`));
|
|
5127
|
+
SEP5();
|
|
4638
5128
|
try {
|
|
4639
5129
|
const { exec } = await import("child_process");
|
|
4640
5130
|
const platform = (await import("os")).platform();
|
|
@@ -4642,17 +5132,17 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
|
|
|
4642
5132
|
const proc = exec(cmd);
|
|
4643
5133
|
proc.stdin?.write(dashboardUrl);
|
|
4644
5134
|
proc.stdin?.end();
|
|
4645
|
-
console.log(
|
|
5135
|
+
console.log(G5(" \u2713 Dashboard URL copied to clipboard"));
|
|
4646
5136
|
} catch {
|
|
4647
5137
|
}
|
|
4648
5138
|
console.log();
|
|
4649
5139
|
} catch (err) {
|
|
4650
|
-
console.error(
|
|
5140
|
+
console.error(chalk9.red(` \u2716 ${formatContractError(err)}`));
|
|
4651
5141
|
process.exit(1);
|
|
4652
5142
|
}
|
|
4653
5143
|
});
|
|
4654
5144
|
syndicate.command("join").description("Request to join a syndicate (creates an EAS attestation)").option("--subdomain <name>", "Syndicate subdomain to join").option("--ref <agentId>", "Referrer agent ID (from invite link)").option("--message <text>", "Message to the creator", "Requesting to join your syndicate").action(async (opts) => {
|
|
4655
|
-
const spinner =
|
|
5145
|
+
const spinner = ora8("Resolving syndicate...").start();
|
|
4656
5146
|
try {
|
|
4657
5147
|
const subdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
|
|
4658
5148
|
if (!subdomain) {
|
|
@@ -4674,17 +5164,17 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
|
|
|
4674
5164
|
try {
|
|
4675
5165
|
const xmtp = await loadXmtp();
|
|
4676
5166
|
await xmtp.getXmtpClient();
|
|
4677
|
-
console.log(
|
|
5167
|
+
console.log(chalk9.dim(" XMTP identity ready"));
|
|
4678
5168
|
} catch {
|
|
4679
|
-
console.warn(
|
|
5169
|
+
console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity"));
|
|
4680
5170
|
}
|
|
4681
5171
|
try {
|
|
4682
5172
|
const cron = await loadCron();
|
|
4683
5173
|
const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
|
|
4684
5174
|
if (cronResult.isOpenClaw && cronResult.registered) {
|
|
4685
|
-
console.log(
|
|
5175
|
+
console.log(chalk9.green(" \u2713 Participation crons registered"));
|
|
4686
5176
|
} else if (!cronResult.isOpenClaw) {
|
|
4687
|
-
console.log(
|
|
5177
|
+
console.log(chalk9.dim(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
|
|
4688
5178
|
}
|
|
4689
5179
|
} catch {
|
|
4690
5180
|
}
|
|
@@ -4697,14 +5187,14 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
|
|
|
4697
5187
|
);
|
|
4698
5188
|
if (existingRequest) {
|
|
4699
5189
|
spinner.succeed("You already have a pending join request for this syndicate");
|
|
4700
|
-
console.log(
|
|
4701
|
-
console.log(
|
|
5190
|
+
console.log(chalk9.dim(` Attestation: ${existingRequest.uid}`));
|
|
5191
|
+
console.log(chalk9.dim(` Submitted: ${new Date(existingRequest.time * 1e3).toLocaleString()}`));
|
|
4702
5192
|
try {
|
|
4703
5193
|
const xmtp = await loadXmtp();
|
|
4704
5194
|
await xmtp.getXmtpClient();
|
|
4705
|
-
console.log(
|
|
5195
|
+
console.log(chalk9.dim(" XMTP identity ready"));
|
|
4706
5196
|
} catch {
|
|
4707
|
-
console.warn(
|
|
5197
|
+
console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity"));
|
|
4708
5198
|
}
|
|
4709
5199
|
return;
|
|
4710
5200
|
}
|
|
@@ -4725,7 +5215,7 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
|
|
|
4725
5215
|
spinner.succeed("Join request created (XMTP identity ready)");
|
|
4726
5216
|
} catch {
|
|
4727
5217
|
spinner.succeed("Join request created");
|
|
4728
|
-
console.warn(
|
|
5218
|
+
console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity \u2014 creator may not be able to auto-add you to chat"));
|
|
4729
5219
|
}
|
|
4730
5220
|
addSyndicate(getChain().id, { subdomain, vault: syndicate2.vault, role: "agent" });
|
|
4731
5221
|
setPrimarySyndicate(getChain().id, subdomain);
|
|
@@ -4733,34 +5223,34 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
|
|
|
4733
5223
|
const cron = await loadCron();
|
|
4734
5224
|
const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
|
|
4735
5225
|
if (cronResult.isOpenClaw && cronResult.registered) {
|
|
4736
|
-
console.log(
|
|
5226
|
+
console.log(G5(" \u2713 Participation crons registered (will activate after approval)"));
|
|
4737
5227
|
} else if (!cronResult.isOpenClaw) {
|
|
4738
|
-
console.log(
|
|
5228
|
+
console.log(DIM5(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
|
|
4739
5229
|
}
|
|
4740
5230
|
} catch {
|
|
4741
5231
|
}
|
|
4742
5232
|
console.log();
|
|
4743
|
-
console.log(
|
|
4744
|
-
|
|
4745
|
-
console.log(
|
|
4746
|
-
console.log(
|
|
4747
|
-
console.log(
|
|
4748
|
-
console.log(
|
|
4749
|
-
console.log(
|
|
4750
|
-
console.log(
|
|
4751
|
-
|
|
4752
|
-
console.log(
|
|
4753
|
-
console.log(
|
|
4754
|
-
console.log(
|
|
5233
|
+
console.log(LABEL5(" \u25C6 Join Request Submitted"));
|
|
5234
|
+
SEP5();
|
|
5235
|
+
console.log(W5(` Syndicate: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
|
|
5236
|
+
console.log(W5(` Agent ID: #${agentId}`));
|
|
5237
|
+
console.log(W5(` Creator: ${DIM5(syndicate2.creator)}`));
|
|
5238
|
+
console.log(W5(` Attestation: ${DIM5(uid)}`));
|
|
5239
|
+
console.log(W5(` EAS Scan: ${DIM5(getEasScanUrl(uid))}`));
|
|
5240
|
+
console.log(W5(` Explorer: ${DIM5(getExplorerUrl(hash))}`));
|
|
5241
|
+
SEP5();
|
|
5242
|
+
console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
|
|
5243
|
+
console.log(G5(" \u2713 The creator can review with:"));
|
|
5244
|
+
console.log(DIM5(` sherwood syndicate requests --subdomain ${subdomain}`));
|
|
4755
5245
|
console.log();
|
|
4756
5246
|
} catch (err) {
|
|
4757
5247
|
spinner.fail("Join request failed");
|
|
4758
|
-
console.error(
|
|
5248
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4759
5249
|
process.exit(1);
|
|
4760
5250
|
}
|
|
4761
5251
|
});
|
|
4762
5252
|
syndicate.command("requests").description("View pending join requests for a syndicate (creator only)").option("--subdomain <name>", "Syndicate subdomain").option("--vault <address>", "Vault address (default: from config)").action(async (opts) => {
|
|
4763
|
-
const spinner =
|
|
5253
|
+
const spinner = ora8("Loading join requests...").start();
|
|
4764
5254
|
try {
|
|
4765
5255
|
let creatorAddress;
|
|
4766
5256
|
let subdomain;
|
|
@@ -4796,39 +5286,39 @@ syndicate.command("requests").description("View pending join requests for a synd
|
|
|
4796
5286
|
);
|
|
4797
5287
|
spinner.stop();
|
|
4798
5288
|
if (requests.length === 0) {
|
|
4799
|
-
console.log(
|
|
5289
|
+
console.log(DIM5("\n No pending join requests.\n"));
|
|
4800
5290
|
return;
|
|
4801
5291
|
}
|
|
4802
5292
|
console.log();
|
|
4803
|
-
console.log(
|
|
4804
|
-
|
|
5293
|
+
console.log(LABEL5(` \u25C6 Pending Join Requests (${requests.length})`));
|
|
5294
|
+
SEP5();
|
|
4805
5295
|
for (let i = 0; i < requests.length; i++) {
|
|
4806
5296
|
const req = requests[i];
|
|
4807
5297
|
const date = new Date(req.time * 1e3).toLocaleString();
|
|
4808
5298
|
const referrer = parseReferrer(req.decoded.message);
|
|
4809
5299
|
const cleanMessage = stripReferrerPrefix(req.decoded.message);
|
|
4810
|
-
console.log(
|
|
4811
|
-
console.log(
|
|
5300
|
+
console.log(W5(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM5(`(${req.attester})`)}`));
|
|
5301
|
+
console.log(DIM5(` Message: "${cleanMessage}"`));
|
|
4812
5302
|
if (referrer !== null) {
|
|
4813
|
-
console.log(
|
|
5303
|
+
console.log(G5(` Referred by: Agent #${referrer}`));
|
|
4814
5304
|
}
|
|
4815
|
-
console.log(
|
|
4816
|
-
console.log(
|
|
5305
|
+
console.log(DIM5(` Requested: ${date}`));
|
|
5306
|
+
console.log(DIM5(` Attestation: ${req.uid}`));
|
|
4817
5307
|
console.log();
|
|
4818
5308
|
}
|
|
4819
|
-
console.log(
|
|
4820
|
-
console.log(
|
|
4821
|
-
console.log(
|
|
4822
|
-
console.log(
|
|
5309
|
+
console.log(G5(" To approve:"));
|
|
5310
|
+
console.log(DIM5(` sherwood syndicate approve --agent-id <id> --wallet <addr>`));
|
|
5311
|
+
console.log(G5(" To reject:"));
|
|
5312
|
+
console.log(DIM5(` sherwood syndicate reject --attestation <uid>`));
|
|
4823
5313
|
console.log();
|
|
4824
5314
|
} catch (err) {
|
|
4825
5315
|
spinner.fail("Failed to load requests");
|
|
4826
|
-
console.error(
|
|
5316
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4827
5317
|
process.exit(1);
|
|
4828
5318
|
}
|
|
4829
5319
|
});
|
|
4830
5320
|
syndicate.command("approve").description("Approve an agent join request (registers agent + creates EAS approval)").option("--vault <address>", "Vault address (default: from config)").option("--subdomain <name>", "Syndicate subdomain (alternative to --vault)").requiredOption("--agent-id <id>", "Agent's ERC-8004 identity token ID").requiredOption("--wallet <address>", "Agent wallet address").action(async (opts) => {
|
|
4831
|
-
const spinner =
|
|
5321
|
+
const spinner = ora8("Verifying creator...").start();
|
|
4832
5322
|
try {
|
|
4833
5323
|
const approveSubdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
|
|
4834
5324
|
if (approveSubdomain && !opts.vault) {
|
|
@@ -4853,11 +5343,11 @@ syndicate.command("approve").description("Approve an agent join request (registe
|
|
|
4853
5343
|
agentWallet
|
|
4854
5344
|
);
|
|
4855
5345
|
agentWasRegistered = true;
|
|
4856
|
-
console.log(
|
|
5346
|
+
console.log(DIM5(` Agent registered: ${getExplorerUrl(regHash)}`));
|
|
4857
5347
|
} catch (regErr) {
|
|
4858
5348
|
const msg = regErr instanceof Error ? regErr.message : String(regErr);
|
|
4859
5349
|
if (msg.includes("0xe098d3ee") || msg.includes("AgentAlreadyRegistered")) {
|
|
4860
|
-
console.log(
|
|
5350
|
+
console.log(DIM5(" Agent already registered on vault \u2014 skipping"));
|
|
4861
5351
|
} else {
|
|
4862
5352
|
throw regErr;
|
|
4863
5353
|
}
|
|
@@ -4873,7 +5363,7 @@ syndicate.command("approve").description("Approve an agent join request (registe
|
|
|
4873
5363
|
let approvalUid;
|
|
4874
5364
|
if (alreadyApproved) {
|
|
4875
5365
|
approvalUid = alreadyApproved.uid;
|
|
4876
|
-
console.log(
|
|
5366
|
+
console.log(DIM5(` Approval attestation already exists \u2014 skipping`));
|
|
4877
5367
|
} else {
|
|
4878
5368
|
spinner.text = "Creating approval attestation...";
|
|
4879
5369
|
const result = await createApproval(
|
|
@@ -4896,48 +5386,48 @@ syndicate.command("approve").description("Approve an agent join request (registe
|
|
|
4896
5386
|
syndicate: subdomain,
|
|
4897
5387
|
timestamp: Math.floor(Date.now() / 1e3)
|
|
4898
5388
|
});
|
|
4899
|
-
console.log(
|
|
5389
|
+
console.log(DIM5(` Added to chat: ${subdomain}`));
|
|
4900
5390
|
} catch {
|
|
4901
|
-
console.warn(
|
|
4902
|
-
console.warn(
|
|
5391
|
+
console.warn(chalk9.yellow(" \u26A0 Could not add agent to chat group"));
|
|
5392
|
+
console.warn(chalk9.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
|
|
4903
5393
|
}
|
|
4904
5394
|
spinner.succeed("Agent approved and registered");
|
|
4905
5395
|
console.log();
|
|
4906
|
-
console.log(
|
|
4907
|
-
|
|
4908
|
-
console.log(
|
|
4909
|
-
console.log(
|
|
4910
|
-
console.log(
|
|
4911
|
-
console.log(
|
|
4912
|
-
|
|
5396
|
+
console.log(LABEL5(" \u25C6 Agent Approved"));
|
|
5397
|
+
SEP5();
|
|
5398
|
+
console.log(W5(` Agent ID: #${opts.agentId}`));
|
|
5399
|
+
console.log(W5(` Wallet: ${G5(opts.wallet)}`));
|
|
5400
|
+
console.log(W5(` Approval: ${DIM5(approvalUid)}`));
|
|
5401
|
+
console.log(W5(` EAS Scan: ${DIM5(getEasScanUrl(approvalUid))}`));
|
|
5402
|
+
SEP5();
|
|
4913
5403
|
} catch (err) {
|
|
4914
5404
|
spinner.fail("Approval failed");
|
|
4915
|
-
console.error(
|
|
5405
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4916
5406
|
process.exit(1);
|
|
4917
5407
|
}
|
|
4918
5408
|
});
|
|
4919
5409
|
syndicate.command("reject").description("Reject a join request by revoking its attestation").requiredOption("--attestation <uid>", "Join request attestation UID to revoke").action(async (opts) => {
|
|
4920
|
-
const spinner =
|
|
5410
|
+
const spinner = ora8("Revoking attestation...").start();
|
|
4921
5411
|
try {
|
|
4922
5412
|
const hash = await revokeAttestation(
|
|
4923
5413
|
EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST,
|
|
4924
5414
|
opts.attestation
|
|
4925
5415
|
);
|
|
4926
5416
|
spinner.succeed("Join request rejected");
|
|
4927
|
-
console.log(
|
|
5417
|
+
console.log(DIM5(` ${getExplorerUrl(hash)}`));
|
|
4928
5418
|
} catch (err) {
|
|
4929
5419
|
spinner.fail("Rejection failed");
|
|
4930
|
-
console.error(
|
|
5420
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
4931
5421
|
process.exit(1);
|
|
4932
5422
|
}
|
|
4933
5423
|
});
|
|
4934
5424
|
syndicate.command("leave").description("Leave a syndicate \u2014 removes participation crons and session state").option("--subdomain <name>", "Syndicate subdomain to leave").action(async (opts) => {
|
|
4935
5425
|
const subdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
|
|
4936
5426
|
if (!subdomain) {
|
|
4937
|
-
console.error(
|
|
5427
|
+
console.error(chalk9.red(" No syndicate configured. Pass --subdomain <name>."));
|
|
4938
5428
|
process.exit(1);
|
|
4939
5429
|
}
|
|
4940
|
-
const spinner =
|
|
5430
|
+
const spinner = ora8("Cleaning up...").start();
|
|
4941
5431
|
try {
|
|
4942
5432
|
let cronsRemoved = false;
|
|
4943
5433
|
try {
|
|
@@ -4950,17 +5440,17 @@ syndicate.command("leave").description("Leave a syndicate \u2014 removes partici
|
|
|
4950
5440
|
resetSession(subdomain);
|
|
4951
5441
|
spinner.succeed("Left syndicate");
|
|
4952
5442
|
if (cronsRemoved) {
|
|
4953
|
-
console.log(
|
|
5443
|
+
console.log(G5(" \u2713 Participation crons removed"));
|
|
4954
5444
|
}
|
|
4955
|
-
console.log(
|
|
5445
|
+
console.log(G5(" \u2713 Session state cleared"));
|
|
4956
5446
|
console.log();
|
|
4957
|
-
console.log(
|
|
4958
|
-
console.log(
|
|
4959
|
-
console.log(
|
|
5447
|
+
console.log(chalk9.dim(" Note: This does not remove you on-chain. To exit your position:"));
|
|
5448
|
+
console.log(chalk9.dim(" sherwood vault balance \u2014 check your LP share balance"));
|
|
5449
|
+
console.log(chalk9.dim(" Redeem shares via the vault contract or dashboard"));
|
|
4960
5450
|
console.log();
|
|
4961
5451
|
} catch (err) {
|
|
4962
5452
|
spinner.fail("Leave failed");
|
|
4963
|
-
console.error(
|
|
5453
|
+
console.error(chalk9.red(err instanceof Error ? err.message : String(err)));
|
|
4964
5454
|
process.exit(1);
|
|
4965
5455
|
}
|
|
4966
5456
|
});
|
|
@@ -4971,21 +5461,21 @@ syndicate.command("set-primary").description("Set the active syndicate for CLI c
|
|
|
4971
5461
|
if (!opts.subdomain && !opts.vault) {
|
|
4972
5462
|
const primary = getPrimarySyndicate(chainId);
|
|
4973
5463
|
if (memberships.length === 0) {
|
|
4974
|
-
console.log(
|
|
5464
|
+
console.log(DIM5("\n No syndicates saved. Create or join one first.\n"));
|
|
4975
5465
|
return;
|
|
4976
5466
|
}
|
|
4977
5467
|
console.log();
|
|
4978
|
-
console.log(
|
|
4979
|
-
|
|
5468
|
+
console.log(LABEL5(" \u25C6 Your Syndicates"));
|
|
5469
|
+
SEP5();
|
|
4980
5470
|
for (const m of memberships) {
|
|
4981
5471
|
const isPrimary = primary?.subdomain === m.subdomain;
|
|
4982
|
-
const marker = isPrimary ?
|
|
4983
|
-
console.log(
|
|
4984
|
-
console.log(
|
|
5472
|
+
const marker = isPrimary ? G5(" \u2605") : "";
|
|
5473
|
+
console.log(W5(` ${m.subdomain}.sherwoodagent.eth${marker} ${DIM5(`(${m.role})`)}`));
|
|
5474
|
+
console.log(DIM5(` vault: ${m.vault}`));
|
|
4985
5475
|
}
|
|
4986
|
-
|
|
5476
|
+
SEP5();
|
|
4987
5477
|
if (memberships.length > 1) {
|
|
4988
|
-
console.log(
|
|
5478
|
+
console.log(DIM5(" Switch with: sherwood syndicate set-primary --subdomain <name>"));
|
|
4989
5479
|
}
|
|
4990
5480
|
console.log();
|
|
4991
5481
|
return;
|
|
@@ -5011,15 +5501,15 @@ syndicate.command("set-primary").description("Set the active syndicate for CLI c
|
|
|
5011
5501
|
}
|
|
5012
5502
|
}
|
|
5013
5503
|
if (!target) {
|
|
5014
|
-
console.error(
|
|
5504
|
+
console.error(chalk9.red(" Could not resolve syndicate. Pass --subdomain or --vault."));
|
|
5015
5505
|
process.exit(1);
|
|
5016
5506
|
}
|
|
5017
5507
|
setPrimarySyndicate(chainId, target);
|
|
5018
|
-
console.log(
|
|
5508
|
+
console.log(G5(`
|
|
5019
5509
|
\u2713 Primary syndicate set to ${target}.sherwoodagent.eth
|
|
5020
5510
|
`));
|
|
5021
5511
|
} catch (err) {
|
|
5022
|
-
console.error(
|
|
5512
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
5023
5513
|
process.exit(1);
|
|
5024
5514
|
}
|
|
5025
5515
|
});
|
|
@@ -5027,18 +5517,18 @@ var vaultCmd = program.command("vault");
|
|
|
5027
5517
|
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)").option("--use-eth", "Auto-wrap ETH \u2192 WETH before depositing (for WETH vaults)").action(async (opts) => {
|
|
5028
5518
|
resolveVault(opts);
|
|
5029
5519
|
const decimals = await getAssetDecimals();
|
|
5030
|
-
const amount =
|
|
5520
|
+
const amount = parseUnits6(opts.amount, decimals);
|
|
5031
5521
|
try {
|
|
5032
5522
|
if (!opts.useEth) {
|
|
5033
5523
|
await preflightDeposit(amount);
|
|
5034
5524
|
}
|
|
5035
5525
|
} catch (err) {
|
|
5036
|
-
console.error(
|
|
5526
|
+
console.error(chalk9.red(`
|
|
5037
5527
|
\u2716 ${err instanceof Error ? err.message : String(err)}
|
|
5038
5528
|
`));
|
|
5039
5529
|
process.exit(1);
|
|
5040
5530
|
}
|
|
5041
|
-
const spinner =
|
|
5531
|
+
const spinner = ora8(`Depositing ${opts.amount}...`).start();
|
|
5042
5532
|
try {
|
|
5043
5533
|
let hash;
|
|
5044
5534
|
if (opts.useEth) {
|
|
@@ -5048,22 +5538,22 @@ vaultCmd.command("deposit").description("Deposit into a vault").option("--vault
|
|
|
5048
5538
|
hash = await deposit(amount);
|
|
5049
5539
|
}
|
|
5050
5540
|
spinner.succeed(`Deposited: ${hash}`);
|
|
5051
|
-
console.log(
|
|
5541
|
+
console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
|
|
5052
5542
|
} catch (err) {
|
|
5053
5543
|
spinner.fail("Deposit failed");
|
|
5054
|
-
console.error(
|
|
5544
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
5055
5545
|
process.exit(1);
|
|
5056
5546
|
}
|
|
5057
5547
|
});
|
|
5058
5548
|
vaultCmd.command("info").description("Display vault state").option("--vault <address>", "Vault address (default: from config)").action(async (opts) => {
|
|
5059
5549
|
resolveVault(opts);
|
|
5060
|
-
const spinner =
|
|
5550
|
+
const spinner = ora8("Loading vault info...").start();
|
|
5061
5551
|
try {
|
|
5062
5552
|
const info = await getVaultInfo();
|
|
5063
5553
|
spinner.stop();
|
|
5064
5554
|
console.log();
|
|
5065
|
-
console.log(
|
|
5066
|
-
console.log(
|
|
5555
|
+
console.log(chalk9.bold("Vault Info"));
|
|
5556
|
+
console.log(chalk9.dim("\u2500".repeat(40)));
|
|
5067
5557
|
console.log(` Address: ${info.address}`);
|
|
5068
5558
|
console.log(` Total Assets: ${info.totalAssets}`);
|
|
5069
5559
|
console.log(` Agent Count: ${info.agentCount}`);
|
|
@@ -5072,26 +5562,26 @@ vaultCmd.command("info").description("Display vault state").option("--vault <add
|
|
|
5072
5562
|
console.log();
|
|
5073
5563
|
} catch (err) {
|
|
5074
5564
|
spinner.fail("Failed to load vault info");
|
|
5075
|
-
console.error(
|
|
5565
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
5076
5566
|
process.exit(1);
|
|
5077
5567
|
}
|
|
5078
5568
|
});
|
|
5079
5569
|
vaultCmd.command("balance").description("Show LP share balance and asset value").option("--vault <address>", "Vault address (default: from config)").option("--address <address>", "Address to check (default: your wallet)").action(async (opts) => {
|
|
5080
5570
|
resolveVault(opts);
|
|
5081
|
-
const spinner =
|
|
5571
|
+
const spinner = ora8("Loading balance...").start();
|
|
5082
5572
|
try {
|
|
5083
5573
|
const balance = await getBalance(opts.address);
|
|
5084
5574
|
spinner.stop();
|
|
5085
5575
|
console.log();
|
|
5086
|
-
console.log(
|
|
5087
|
-
console.log(
|
|
5576
|
+
console.log(chalk9.bold("LP Position"));
|
|
5577
|
+
console.log(chalk9.dim("\u2500".repeat(40)));
|
|
5088
5578
|
console.log(` Shares: ${balance.shares.toString()}`);
|
|
5089
5579
|
console.log(` Asset Value: ${balance.assetsValue}`);
|
|
5090
5580
|
console.log(` % of Vault: ${balance.percentOfVault}`);
|
|
5091
5581
|
console.log();
|
|
5092
5582
|
} catch (err) {
|
|
5093
5583
|
spinner.fail("Failed to load balance");
|
|
5094
|
-
console.error(
|
|
5584
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
5095
5585
|
process.exit(1);
|
|
5096
5586
|
}
|
|
5097
5587
|
});
|
|
@@ -5102,22 +5592,22 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
|
|
|
5102
5592
|
let shares;
|
|
5103
5593
|
try {
|
|
5104
5594
|
if (opts.shares) {
|
|
5105
|
-
shares =
|
|
5595
|
+
shares = parseUnits6(opts.shares, shareDecimals);
|
|
5106
5596
|
} else {
|
|
5107
5597
|
shares = await getShareBalance();
|
|
5108
5598
|
if (shares === 0n) {
|
|
5109
|
-
console.error(
|
|
5599
|
+
console.error(chalk9.red("\n \u2716 No shares to redeem.\n"));
|
|
5110
5600
|
process.exit(1);
|
|
5111
5601
|
}
|
|
5112
5602
|
}
|
|
5113
5603
|
} catch (err) {
|
|
5114
|
-
console.error(
|
|
5604
|
+
console.error(chalk9.red(`
|
|
5115
5605
|
\u2716 ${err instanceof Error ? err.message : String(err)}
|
|
5116
5606
|
`));
|
|
5117
5607
|
process.exit(1);
|
|
5118
5608
|
}
|
|
5119
|
-
if (opts.receiver && !
|
|
5120
|
-
console.error(
|
|
5609
|
+
if (opts.receiver && !isAddress6(opts.receiver)) {
|
|
5610
|
+
console.error(chalk9.red(`
|
|
5121
5611
|
\u2716 Invalid receiver address: ${opts.receiver}
|
|
5122
5612
|
`));
|
|
5123
5613
|
process.exit(1);
|
|
@@ -5125,24 +5615,24 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
|
|
|
5125
5615
|
try {
|
|
5126
5616
|
await preflightRedeem(shares);
|
|
5127
5617
|
} catch (err) {
|
|
5128
|
-
console.error(
|
|
5618
|
+
console.error(chalk9.red(`
|
|
5129
5619
|
\u2716 ${err instanceof Error ? err.message : String(err)}
|
|
5130
5620
|
`));
|
|
5131
5621
|
process.exit(1);
|
|
5132
5622
|
}
|
|
5133
|
-
const sharesDisplay =
|
|
5134
|
-
const spinner =
|
|
5623
|
+
const sharesDisplay = formatUnits5(shares, shareDecimals);
|
|
5624
|
+
const spinner = ora8(`Redeeming ${sharesDisplay} shares...`).start();
|
|
5135
5625
|
try {
|
|
5136
5626
|
const { hash, assetsOut } = await redeem(
|
|
5137
5627
|
shares,
|
|
5138
5628
|
opts.receiver
|
|
5139
5629
|
);
|
|
5140
5630
|
spinner.succeed(`Redeemed: ${hash}`);
|
|
5141
|
-
console.log(
|
|
5142
|
-
console.log(` Assets received: ${
|
|
5631
|
+
console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
|
|
5632
|
+
console.log(` Assets received: ${formatUnits5(assetsOut, assetDecimals)}`);
|
|
5143
5633
|
} catch (err) {
|
|
5144
5634
|
spinner.fail("Redeem failed");
|
|
5145
|
-
console.error(
|
|
5635
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
5146
5636
|
process.exit(1);
|
|
5147
5637
|
}
|
|
5148
5638
|
});
|
|
@@ -5160,28 +5650,29 @@ ${info.name} (${info.type})`);
|
|
|
5160
5650
|
}
|
|
5161
5651
|
});
|
|
5162
5652
|
try {
|
|
5163
|
-
const { registerChatCommands } = await import("./chat-
|
|
5653
|
+
const { registerChatCommands } = await import("./chat-3GE6474H.js");
|
|
5164
5654
|
registerChatCommands(program);
|
|
5165
5655
|
} catch {
|
|
5166
5656
|
program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
|
|
5167
|
-
console.error(
|
|
5168
|
-
console.error(
|
|
5169
|
-
console.error(
|
|
5657
|
+
console.error(chalk9.red("XMTP CLI not available."));
|
|
5658
|
+
console.error(chalk9.dim("Install with: npm install -g @xmtp/cli"));
|
|
5659
|
+
console.error(chalk9.dim("Or reinstall: npm i -g @sherwoodagent/cli"));
|
|
5170
5660
|
process.exit(1);
|
|
5171
5661
|
});
|
|
5172
5662
|
}
|
|
5173
|
-
var { registerSessionCommands } = await import("./session-
|
|
5663
|
+
var { registerSessionCommands } = await import("./session-EST3O7W3.js");
|
|
5174
5664
|
registerSessionCommands(program);
|
|
5175
5665
|
registerVeniceCommands(program);
|
|
5176
5666
|
registerAllowanceCommands(program);
|
|
5177
5667
|
registerIdentityCommands(program);
|
|
5178
5668
|
registerProposalCommands(program);
|
|
5179
5669
|
registerGovernorCommands(program);
|
|
5180
|
-
|
|
5670
|
+
registerGuardianCommands(program);
|
|
5671
|
+
var { registerResearchCommands } = await import("./research-HDEPP2SL.js");
|
|
5181
5672
|
registerResearchCommands(program);
|
|
5182
|
-
var { registerAgentCommands } = await import("./agent-
|
|
5673
|
+
var { registerAgentCommands } = await import("./agent-LBF6OZRW.js");
|
|
5183
5674
|
registerAgentCommands(program);
|
|
5184
|
-
var { registerTradeCommands } = await import("./trade-
|
|
5675
|
+
var { registerTradeCommands } = await import("./trade-XTLUZJB6.js");
|
|
5185
5676
|
registerTradeCommands(program);
|
|
5186
5677
|
var configCmd = program.command("config");
|
|
5187
5678
|
configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").option("--rpc <url>", "Custom RPC URL for the active --chain network").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").option("--uniswap-api-key <key>", "Uniswap Trading API key (from developers.uniswap.org)").option("--venice-api-key <key>", "Venice AI inference API key").option("--xmtp-group <subdomain:groupId>", "Cache an XMTP group ID for a syndicate (e.g. my-fund:abc123)").action((opts) => {
|
|
@@ -5189,53 +5680,53 @@ configCmd.command("set").description("Save settings to ~/.sherwood/config.json (
|
|
|
5189
5680
|
if (opts.privateKey) {
|
|
5190
5681
|
setPrivateKey(opts.privateKey);
|
|
5191
5682
|
const account = getAccount();
|
|
5192
|
-
console.log(
|
|
5193
|
-
console.log(
|
|
5683
|
+
console.log(chalk9.green("Private key saved to ~/.sherwood/config.json"));
|
|
5684
|
+
console.log(chalk9.dim(` Wallet: ${account.address}`));
|
|
5194
5685
|
saved = true;
|
|
5195
5686
|
}
|
|
5196
5687
|
if (opts.vault) {
|
|
5197
5688
|
const chainId = getChain().id;
|
|
5198
5689
|
setChainContract(chainId, "vault", opts.vault);
|
|
5199
|
-
console.log(
|
|
5200
|
-
console.log(
|
|
5690
|
+
console.log(chalk9.green(`Vault saved to ~/.sherwood/config.json (chain ${chainId})`));
|
|
5691
|
+
console.log(chalk9.dim(` Vault: ${opts.vault}`));
|
|
5201
5692
|
saved = true;
|
|
5202
5693
|
}
|
|
5203
5694
|
if (opts.rpc) {
|
|
5204
5695
|
const network = getNetwork();
|
|
5205
5696
|
setConfigRpcUrl(network, opts.rpc);
|
|
5206
|
-
console.log(
|
|
5207
|
-
console.log(
|
|
5697
|
+
console.log(chalk9.green(`RPC URL saved for ${network}`));
|
|
5698
|
+
console.log(chalk9.dim(` RPC: ${opts.rpc}`));
|
|
5208
5699
|
saved = true;
|
|
5209
5700
|
}
|
|
5210
5701
|
if (opts.notifyTo) {
|
|
5211
5702
|
setNotifyTo(opts.notifyTo);
|
|
5212
|
-
console.log(
|
|
5213
|
-
console.log(
|
|
5703
|
+
console.log(chalk9.green("Notify destination saved to ~/.sherwood/config.json"));
|
|
5704
|
+
console.log(chalk9.dim(` Notify to: ${opts.notifyTo}`));
|
|
5214
5705
|
saved = true;
|
|
5215
5706
|
}
|
|
5216
5707
|
if (opts.uniswapApiKey) {
|
|
5217
5708
|
setUniswapApiKey(opts.uniswapApiKey);
|
|
5218
|
-
console.log(
|
|
5709
|
+
console.log(chalk9.green("Uniswap API key saved to ~/.sherwood/config.json"));
|
|
5219
5710
|
saved = true;
|
|
5220
5711
|
}
|
|
5221
5712
|
if (opts.veniceApiKey) {
|
|
5222
5713
|
setVeniceApiKey(opts.veniceApiKey);
|
|
5223
|
-
console.log(
|
|
5714
|
+
console.log(chalk9.green("Venice API key saved to ~/.sherwood/config.json"));
|
|
5224
5715
|
saved = true;
|
|
5225
5716
|
}
|
|
5226
5717
|
if (opts.xmtpGroup) {
|
|
5227
5718
|
const parts = opts.xmtpGroup.split(":");
|
|
5228
5719
|
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
5229
|
-
console.log(
|
|
5720
|
+
console.log(chalk9.red("Format: --xmtp-group <subdomain>:<groupId>"));
|
|
5230
5721
|
process.exit(1);
|
|
5231
5722
|
}
|
|
5232
5723
|
cacheGroupId(parts[0], parts[1]);
|
|
5233
|
-
console.log(
|
|
5234
|
-
console.log(
|
|
5724
|
+
console.log(chalk9.green(`XMTP group ID cached for ${parts[0]}`));
|
|
5725
|
+
console.log(chalk9.dim(` Group ID: ${parts[1]}`));
|
|
5235
5726
|
saved = true;
|
|
5236
5727
|
}
|
|
5237
5728
|
if (!saved) {
|
|
5238
|
-
console.log(
|
|
5729
|
+
console.log(chalk9.red("Provide at least one of: --private-key, --vault, --rpc, --notify-to, --uniswap-api-key, --venice-api-key, --xmtp-group"));
|
|
5239
5730
|
process.exit(1);
|
|
5240
5731
|
}
|
|
5241
5732
|
});
|
|
@@ -5246,25 +5737,25 @@ configCmd.command("show").description("Display current config for the active net
|
|
|
5246
5737
|
const config = loadConfig();
|
|
5247
5738
|
const customRpc = config.rpc?.[network];
|
|
5248
5739
|
console.log();
|
|
5249
|
-
console.log(
|
|
5250
|
-
console.log(
|
|
5251
|
-
console.log(` Network: ${
|
|
5252
|
-
console.log(` RPC: ${customRpc ?
|
|
5253
|
-
console.log(` Wallet: ${config.privateKey ?
|
|
5254
|
-
console.log(` Agent ID: ${config.agentId ??
|
|
5255
|
-
console.log(` Vault: ${contracts.vault ??
|
|
5256
|
-
console.log(` Uniswap: ${getUniswapApiKey() ?
|
|
5257
|
-
console.log(` Venice: ${getVeniceApiKey() ?
|
|
5740
|
+
console.log(chalk9.bold(`Sherwood Config`));
|
|
5741
|
+
console.log(chalk9.dim("\u2500".repeat(50)));
|
|
5742
|
+
console.log(` Network: ${chalk9.cyan(network)} (chain ${chainId})`);
|
|
5743
|
+
console.log(` RPC: ${customRpc ? chalk9.green(customRpc) : chalk9.dim("default")}`);
|
|
5744
|
+
console.log(` Wallet: ${config.privateKey ? chalk9.green("configured") : chalk9.dim("not set")}`);
|
|
5745
|
+
console.log(` Agent ID: ${config.agentId ?? chalk9.dim("not set")}`);
|
|
5746
|
+
console.log(` Vault: ${contracts.vault ?? chalk9.dim("not set")}`);
|
|
5747
|
+
console.log(` Uniswap: ${getUniswapApiKey() ? chalk9.green("API key configured") : chalk9.dim("not set")}`);
|
|
5748
|
+
console.log(` Venice: ${getVeniceApiKey() ? chalk9.green("API key configured") : chalk9.dim("not set")}`);
|
|
5258
5749
|
const groupEntries = Object.entries(config.groupCache || {}).filter(([, v]) => v);
|
|
5259
5750
|
if (groupEntries.length > 0) {
|
|
5260
5751
|
console.log();
|
|
5261
|
-
console.log(
|
|
5752
|
+
console.log(chalk9.bold(" XMTP Groups"));
|
|
5262
5753
|
for (const [sub, gid] of groupEntries) {
|
|
5263
|
-
console.log(` ${sub}: ${
|
|
5754
|
+
console.log(` ${sub}: ${chalk9.cyan(gid)}`);
|
|
5264
5755
|
}
|
|
5265
5756
|
}
|
|
5266
5757
|
console.log();
|
|
5267
|
-
console.log(
|
|
5758
|
+
console.log(chalk9.dim(" Config file: ~/.sherwood/config.json"));
|
|
5268
5759
|
console.log();
|
|
5269
5760
|
});
|
|
5270
5761
|
program.parse();
|