@sherwoodagent/cli 0.83.1 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abis-ZQ6I3S6L.js → abis-WVW2EBI3.js} +2 -2
- package/dist/{addresses-MS6BB7AB.js → addresses-LFYVOPOH.js} +3 -3
- package/dist/{agent-C5XZSK7Z.js → agent-TBLC3WNJ.js} +7 -7
- package/dist/{chat-FGTYCJ4B.js → chat-UZ3BBEXV.js} +8 -8
- package/dist/{chunk-G34TNE53.js → chunk-45FELUWY.js} +2 -2
- package/dist/{chunk-4WAEM2TC.js → chunk-56YYNNNQ.js} +5 -5
- package/dist/{chunk-AJ46XIGY.js → chunk-6DRNSZ2Z.js} +41 -5
- package/dist/chunk-6DRNSZ2Z.js.map +1 -0
- package/dist/{chunk-4GO7I33U.js → chunk-BOC7VB5B.js} +36 -5
- package/dist/chunk-BOC7VB5B.js.map +1 -0
- package/dist/{chunk-I7TMY7AS.js → chunk-DNRIKCJ5.js} +85 -31
- package/dist/chunk-DNRIKCJ5.js.map +1 -0
- package/dist/{chunk-XSP64L7L.js → chunk-F3MDCUGO.js} +4 -368
- package/dist/chunk-F3MDCUGO.js.map +1 -0
- package/dist/{chunk-NKRMMFQG.js → chunk-JUVXLTL2.js} +56 -5
- package/dist/chunk-JUVXLTL2.js.map +1 -0
- package/dist/{chunk-CCNOXDZ7.js → chunk-KVB5P2OE.js} +2 -2
- package/dist/{chunk-MBWFTXF5.js → chunk-MQ55QOGD.js} +5 -5
- package/dist/{chunk-M34JVPJO.js → chunk-NCFN66ZH.js} +39 -6
- package/dist/chunk-NCFN66ZH.js.map +1 -0
- package/dist/{chunk-ZW2VKCFZ.js → chunk-PVTZMRC6.js} +34 -2
- package/dist/chunk-PVTZMRC6.js.map +1 -0
- package/dist/{chunk-AQPTBVEA.js → chunk-QRMZRAMG.js} +2 -2
- package/dist/{chunk-AOL2DJTK.js → chunk-SNR5R5TO.js} +6 -6
- package/dist/{client-OPZ2ORWW.js → client-3SE632Q2.js} +3 -3
- package/dist/{eas-32PEJETG.js → eas-QPKX6A5A.js} +12 -6
- package/dist/{governor-GSCXEZWI.js → governor-7QKGNHMR.js} +12 -6
- package/dist/index.js +1053 -269
- package/dist/index.js.map +1 -1
- package/dist/{network-HCFCNZUI.js → network-FEHRFDPJ.js} +6 -2
- package/dist/{price-OUL7WIXQ.js → price-SVF25X4O.js} +6 -6
- package/dist/{providers-4HQHB7V5.js → providers-BMOHHVUN.js} +4 -4
- package/dist/{research-2RWAMWWH.js → research-YSNJ5HTM.js} +15 -12
- package/dist/research-YSNJ5HTM.js.map +1 -0
- package/dist/{session-SIOJZO6P.js → session-RMAIFRS6.js} +44 -13
- package/dist/session-RMAIFRS6.js.map +1 -0
- package/dist/{trade-ZEIY3MCL.js → trade-YPLTIS56.js} +21 -21
- package/dist/trade-YPLTIS56.js.map +1 -0
- package/dist/{vault-VDADZFSV.js → vault-UCFFOOTS.js} +8 -8
- package/dist/{xmtp-2U7CSBXM.js → xmtp-S7IGTIMZ.js} +6 -6
- package/package.json +2 -2
- package/dist/chunk-4GO7I33U.js.map +0 -1
- package/dist/chunk-AJ46XIGY.js.map +0 -1
- package/dist/chunk-I7TMY7AS.js.map +0 -1
- package/dist/chunk-M34JVPJO.js.map +0 -1
- package/dist/chunk-NKRMMFQG.js.map +0 -1
- package/dist/chunk-XSP64L7L.js.map +0 -1
- package/dist/chunk-ZW2VKCFZ.js.map +0 -1
- package/dist/research-2RWAMWWH.js.map +0 -1
- package/dist/session-SIOJZO6P.js.map +0 -1
- package/dist/trade-ZEIY3MCL.js.map +0 -1
- /package/dist/{abis-ZQ6I3S6L.js.map → abis-WVW2EBI3.js.map} +0 -0
- /package/dist/{addresses-MS6BB7AB.js.map → addresses-LFYVOPOH.js.map} +0 -0
- /package/dist/{agent-C5XZSK7Z.js.map → agent-TBLC3WNJ.js.map} +0 -0
- /package/dist/{chat-FGTYCJ4B.js.map → chat-UZ3BBEXV.js.map} +0 -0
- /package/dist/{chunk-G34TNE53.js.map → chunk-45FELUWY.js.map} +0 -0
- /package/dist/{chunk-4WAEM2TC.js.map → chunk-56YYNNNQ.js.map} +0 -0
- /package/dist/{chunk-CCNOXDZ7.js.map → chunk-KVB5P2OE.js.map} +0 -0
- /package/dist/{chunk-MBWFTXF5.js.map → chunk-MQ55QOGD.js.map} +0 -0
- /package/dist/{chunk-AQPTBVEA.js.map → chunk-QRMZRAMG.js.map} +0 -0
- /package/dist/{chunk-AOL2DJTK.js.map → chunk-SNR5R5TO.js.map} +0 -0
- /package/dist/{client-OPZ2ORWW.js.map → client-3SE632Q2.js.map} +0 -0
- /package/dist/{eas-32PEJETG.js.map → eas-QPKX6A5A.js.map} +0 -0
- /package/dist/{governor-GSCXEZWI.js.map → governor-7QKGNHMR.js.map} +0 -0
- /package/dist/{network-HCFCNZUI.js.map → network-FEHRFDPJ.js.map} +0 -0
- /package/dist/{price-OUL7WIXQ.js.map → price-SVF25X4O.js.map} +0 -0
- /package/dist/{providers-4HQHB7V5.js.map → providers-BMOHHVUN.js.map} +0 -0
- /package/dist/{vault-VDADZFSV.js.map → vault-UCFFOOTS.js.map} +0 -0
- /package/dist/{xmtp-2U7CSBXM.js.map → xmtp-S7IGTIMZ.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
checkApiKeyValid,
|
|
16
16
|
listModels,
|
|
17
17
|
provisionApiKey
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KVB5P2OE.js";
|
|
19
19
|
import {
|
|
20
20
|
approveDepositor,
|
|
21
21
|
deposit,
|
|
@@ -38,50 +38,55 @@ import {
|
|
|
38
38
|
removeDepositor,
|
|
39
39
|
setAgentFeeBps,
|
|
40
40
|
setVaultAddress
|
|
41
|
-
} from "./chunk-
|
|
42
|
-
import "./chunk-
|
|
41
|
+
} from "./chunk-SNR5R5TO.js";
|
|
42
|
+
import "./chunk-JUVXLTL2.js";
|
|
43
43
|
import {
|
|
44
|
+
DEFAULT_FEE_TIER,
|
|
44
45
|
HYPERLIQUID_PERP_STRATEGY_ABI,
|
|
45
46
|
applySlippage,
|
|
46
47
|
assetDecimalsForSymbol,
|
|
47
48
|
buildCallsForTemplate,
|
|
48
49
|
buildInitDataForTemplate,
|
|
49
50
|
computeProposalAssetChecks,
|
|
51
|
+
defaultPortfolioAsset,
|
|
50
52
|
encodeSwapPath,
|
|
51
53
|
getMultiHopQuote,
|
|
52
54
|
getQuote,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
parseAlignedOverrides,
|
|
56
|
+
resolveToken,
|
|
57
|
+
selectBestFeeTier
|
|
58
|
+
} from "./chunk-6DRNSZ2Z.js";
|
|
55
59
|
import {
|
|
56
60
|
createApproval,
|
|
57
61
|
createJoinRequest,
|
|
58
62
|
getEasExplorerUrl,
|
|
59
|
-
getEasScanUrl,
|
|
60
63
|
parseReferrer,
|
|
61
64
|
queryApprovals,
|
|
62
65
|
queryJoinRequests,
|
|
63
66
|
revokeJoinRequest,
|
|
64
67
|
stripReferrerPrefix
|
|
65
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-NCFN66ZH.js";
|
|
66
69
|
import {
|
|
67
70
|
createFund,
|
|
68
71
|
getActiveFunds,
|
|
69
72
|
getFund,
|
|
70
73
|
subdomainExists,
|
|
71
74
|
updateMetadata
|
|
72
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-56YYNNNQ.js";
|
|
73
76
|
import {
|
|
74
77
|
resolveFund,
|
|
75
78
|
resolveVaultFund,
|
|
76
79
|
searchFundAcrossChains,
|
|
77
80
|
setTextRecord
|
|
78
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-MQ55QOGD.js";
|
|
79
82
|
import {
|
|
80
83
|
PROPOSAL_STATE,
|
|
81
84
|
PROPOSAL_STATES,
|
|
82
85
|
VOTE_TYPE,
|
|
86
|
+
assertReceiptSuccess,
|
|
83
87
|
cancelProposal,
|
|
84
88
|
classifyReview,
|
|
89
|
+
classifyReviewOpen,
|
|
85
90
|
emergencyCancel,
|
|
86
91
|
emergencySettle,
|
|
87
92
|
evaluateExecuteGate,
|
|
@@ -98,8 +103,10 @@ import {
|
|
|
98
103
|
getVoteWeight,
|
|
99
104
|
hasVoted,
|
|
100
105
|
parseDuration,
|
|
106
|
+
parseProposalIdFromLogs,
|
|
101
107
|
proposalCount,
|
|
102
108
|
propose,
|
|
109
|
+
scanReviewCandidates,
|
|
103
110
|
setCooldownPeriod,
|
|
104
111
|
setExecutionWindow,
|
|
105
112
|
setMaxPerformanceFeeBps,
|
|
@@ -109,7 +116,7 @@ import {
|
|
|
109
116
|
setVotingPeriod,
|
|
110
117
|
settleProposal,
|
|
111
118
|
vote
|
|
112
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-BOC7VB5B.js";
|
|
113
120
|
import {
|
|
114
121
|
AERODROME,
|
|
115
122
|
AGENT_REGISTRY,
|
|
@@ -119,7 +126,7 @@ import {
|
|
|
119
126
|
TOKENS,
|
|
120
127
|
UNISWAP,
|
|
121
128
|
VENICE
|
|
122
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-DNRIKCJ5.js";
|
|
123
130
|
import {
|
|
124
131
|
GAS_UNITS,
|
|
125
132
|
estimateGasCushion,
|
|
@@ -130,7 +137,7 @@ import {
|
|
|
130
137
|
sendTxWithRetry,
|
|
131
138
|
waitForReceipt,
|
|
132
139
|
writeContractWithRetry
|
|
133
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-QRMZRAMG.js";
|
|
134
141
|
import {
|
|
135
142
|
DEFAULT_NETWORK,
|
|
136
143
|
VALID_NETWORKS,
|
|
@@ -142,7 +149,7 @@ import {
|
|
|
142
149
|
isTestnet,
|
|
143
150
|
setNetwork,
|
|
144
151
|
withNetwork
|
|
145
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-PVTZMRC6.js";
|
|
146
153
|
import {
|
|
147
154
|
addFund,
|
|
148
155
|
cacheGroupId,
|
|
@@ -178,7 +185,7 @@ import {
|
|
|
178
185
|
SWAP_ROUTER_EXACT_INPUT_SINGLE_ABI,
|
|
179
186
|
SYNDICATE_VAULT_ABI,
|
|
180
187
|
VENICE_STAKING_ABI
|
|
181
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-F3MDCUGO.js";
|
|
182
189
|
import {
|
|
183
190
|
fetchMetadata,
|
|
184
191
|
mergeFundMetadata,
|
|
@@ -289,7 +296,7 @@ var HYPERLIQUID_GRID_STRATEGY_ABI = [
|
|
|
289
296
|
];
|
|
290
297
|
|
|
291
298
|
// src/commands/strategy-template-lib.ts
|
|
292
|
-
import { parseUnits as parseUnits2, formatUnits as formatUnits4, erc20Abi } from "viem";
|
|
299
|
+
import { parseUnits as parseUnits2, formatUnits as formatUnits4, isAddress as isAddress3, erc20Abi } from "viem";
|
|
293
300
|
import chalk2 from "chalk";
|
|
294
301
|
|
|
295
302
|
// src/lib/proposer-bond-error.ts
|
|
@@ -324,6 +331,13 @@ function emitCalldata(action) {
|
|
|
324
331
|
process.stdout.write(JSON.stringify(action, null, 2) + "\n");
|
|
325
332
|
}
|
|
326
333
|
|
|
334
|
+
// ../sdk/dist/generated/state-machines.js
|
|
335
|
+
var GUARDIAN_VOTE_TYPES = [
|
|
336
|
+
"None",
|
|
337
|
+
"Approve",
|
|
338
|
+
"Block"
|
|
339
|
+
];
|
|
340
|
+
|
|
327
341
|
// ../sdk/dist/types.js
|
|
328
342
|
var CHAIN_IDS = {
|
|
329
343
|
BASE: 8453,
|
|
@@ -519,6 +533,27 @@ var SYNDICATE_VAULT_ABI2 = [
|
|
|
519
533
|
{ name: "agentId", type: "uint256" }
|
|
520
534
|
],
|
|
521
535
|
outputs: []
|
|
536
|
+
},
|
|
537
|
+
// Governor-only: mint + fund + run a single-use CallSandbox.
|
|
538
|
+
// ICallSandbox.Call is TWO fields (address,bytes). There is NO `value`.
|
|
539
|
+
{
|
|
540
|
+
name: "runSandbox",
|
|
541
|
+
type: "function",
|
|
542
|
+
stateMutability: "nonpayable",
|
|
543
|
+
inputs: [
|
|
544
|
+
{ name: "pid", type: "uint256" },
|
|
545
|
+
{
|
|
546
|
+
name: "calls",
|
|
547
|
+
type: "tuple[]",
|
|
548
|
+
components: [
|
|
549
|
+
{ name: "target", type: "address" },
|
|
550
|
+
{ name: "data", type: "bytes" }
|
|
551
|
+
]
|
|
552
|
+
},
|
|
553
|
+
{ name: "declaredTokens", type: "address[]" },
|
|
554
|
+
{ name: "funding", type: "uint256" }
|
|
555
|
+
],
|
|
556
|
+
outputs: [{ name: "sandbox", type: "address" }]
|
|
522
557
|
}
|
|
523
558
|
];
|
|
524
559
|
var SYNDICATE_GOVERNOR_ABI = [
|
|
@@ -580,6 +615,74 @@ var SYNDICATE_GOVERNOR_ABI = [
|
|
|
580
615
|
],
|
|
581
616
|
outputs: [{ name: "proposalId", type: "uint256" }]
|
|
582
617
|
},
|
|
618
|
+
// proposeWithSandbox — same 10 args as propose, prefixed with SandboxPayload.
|
|
619
|
+
// ICallSandbox.Call is TWO fields (address,bytes). There is NO `value`:
|
|
620
|
+
// native value would open a transfer channel with no metering story
|
|
621
|
+
// (ICallSandbox.sol:44-51). Aliasing BatchExecutorLib.Call would reintroduce it.
|
|
622
|
+
{
|
|
623
|
+
name: "proposeWithSandbox",
|
|
624
|
+
type: "function",
|
|
625
|
+
stateMutability: "nonpayable",
|
|
626
|
+
inputs: [
|
|
627
|
+
{
|
|
628
|
+
name: "sandbox",
|
|
629
|
+
type: "tuple",
|
|
630
|
+
components: [
|
|
631
|
+
{ name: "funding", type: "uint256" },
|
|
632
|
+
{
|
|
633
|
+
name: "calls",
|
|
634
|
+
type: "tuple[]",
|
|
635
|
+
components: [
|
|
636
|
+
{ name: "target", type: "address" },
|
|
637
|
+
{ name: "data", type: "bytes" }
|
|
638
|
+
]
|
|
639
|
+
},
|
|
640
|
+
{ name: "declaredTokens", type: "address[]" }
|
|
641
|
+
]
|
|
642
|
+
},
|
|
643
|
+
{ name: "vault", type: "address" },
|
|
644
|
+
{ name: "strategy", type: "address" },
|
|
645
|
+
{ name: "metadataURI", type: "string" },
|
|
646
|
+
{ name: "strategyDuration", type: "uint256" },
|
|
647
|
+
{
|
|
648
|
+
name: "envelope",
|
|
649
|
+
type: "tuple",
|
|
650
|
+
components: [
|
|
651
|
+
{ name: "maxCapital", type: "uint256" },
|
|
652
|
+
{ name: "maxDrawdownBps", type: "uint16" }
|
|
653
|
+
]
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
name: "executeCalls",
|
|
657
|
+
type: "tuple[]",
|
|
658
|
+
components: [
|
|
659
|
+
{ name: "target", type: "address" },
|
|
660
|
+
{ name: "data", type: "bytes" },
|
|
661
|
+
{ name: "value", type: "uint256" }
|
|
662
|
+
]
|
|
663
|
+
},
|
|
664
|
+
{ name: "executeCallCaps", type: "uint256[]" },
|
|
665
|
+
{
|
|
666
|
+
name: "settlementCalls",
|
|
667
|
+
type: "tuple[]",
|
|
668
|
+
components: [
|
|
669
|
+
{ name: "target", type: "address" },
|
|
670
|
+
{ name: "data", type: "bytes" },
|
|
671
|
+
{ name: "value", type: "uint256" }
|
|
672
|
+
]
|
|
673
|
+
},
|
|
674
|
+
{ name: "settlementCallCaps", type: "uint256[]" },
|
|
675
|
+
{
|
|
676
|
+
name: "coProposers",
|
|
677
|
+
type: "tuple[]",
|
|
678
|
+
components: [
|
|
679
|
+
{ name: "agent", type: "address" },
|
|
680
|
+
{ name: "splitBps", type: "uint256" }
|
|
681
|
+
]
|
|
682
|
+
}
|
|
683
|
+
],
|
|
684
|
+
outputs: [{ name: "proposalId", type: "uint256" }]
|
|
685
|
+
},
|
|
583
686
|
// Lifecycle writes
|
|
584
687
|
{
|
|
585
688
|
name: "vote",
|
|
@@ -720,6 +823,35 @@ var SYNDICATE_GOVERNOR_ABI = [
|
|
|
720
823
|
}
|
|
721
824
|
]
|
|
722
825
|
},
|
|
826
|
+
// sandboxPayload — ISyndicateGovernor.sol ~730 / SyndicateGovernor.sol:506.
|
|
827
|
+
// Returns SandboxPayload {funding, calls, declaredTokens}. Calls are
|
|
828
|
+
// ICallSandbox.Call = (address target, bytes data) ONLY — no `value`.
|
|
829
|
+
// Non-sandbox (and unknown) pids return the mapping default: zero funding,
|
|
830
|
+
// empty calls, empty declaredTokens. The contract does not revert.
|
|
831
|
+
{
|
|
832
|
+
name: "sandboxPayload",
|
|
833
|
+
type: "function",
|
|
834
|
+
stateMutability: "view",
|
|
835
|
+
inputs: [{ name: "proposalId", type: "uint256" }],
|
|
836
|
+
outputs: [
|
|
837
|
+
{
|
|
838
|
+
name: "payload",
|
|
839
|
+
type: "tuple",
|
|
840
|
+
components: [
|
|
841
|
+
{ name: "funding", type: "uint256" },
|
|
842
|
+
{
|
|
843
|
+
name: "calls",
|
|
844
|
+
type: "tuple[]",
|
|
845
|
+
components: [
|
|
846
|
+
{ name: "target", type: "address" },
|
|
847
|
+
{ name: "data", type: "bytes" }
|
|
848
|
+
]
|
|
849
|
+
},
|
|
850
|
+
{ name: "declaredTokens", type: "address[]" }
|
|
851
|
+
]
|
|
852
|
+
}
|
|
853
|
+
]
|
|
854
|
+
},
|
|
723
855
|
{
|
|
724
856
|
name: "getProposalState",
|
|
725
857
|
type: "function",
|
|
@@ -942,60 +1074,64 @@ var GUARDIAN_REGISTRY_ABI = [
|
|
|
942
1074
|
inputs: [],
|
|
943
1075
|
outputs: []
|
|
944
1076
|
},
|
|
945
|
-
// Delegation
|
|
1077
|
+
// Delegation and commission fragments removed (SHE-86): delegateStake,
|
|
1078
|
+
// requestUnstakeDelegation, cancelUnstakeDelegation, claimUnstakeDelegation
|
|
1079
|
+
// and setCommission do not exist on the post-audit contracts.
|
|
1080
|
+
// Reads
|
|
946
1081
|
{
|
|
947
|
-
name: "
|
|
1082
|
+
name: "guardianStake",
|
|
948
1083
|
type: "function",
|
|
949
|
-
stateMutability: "
|
|
950
|
-
inputs: [
|
|
951
|
-
|
|
952
|
-
{ name: "amount", type: "uint256" }
|
|
953
|
-
],
|
|
954
|
-
outputs: []
|
|
1084
|
+
stateMutability: "view",
|
|
1085
|
+
inputs: [{ name: "guardian", type: "address" }],
|
|
1086
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
955
1087
|
},
|
|
956
1088
|
{
|
|
957
|
-
name: "
|
|
1089
|
+
name: "isActiveGuardian",
|
|
958
1090
|
type: "function",
|
|
959
|
-
stateMutability: "
|
|
960
|
-
inputs: [{ name: "
|
|
961
|
-
outputs: []
|
|
1091
|
+
stateMutability: "view",
|
|
1092
|
+
inputs: [{ name: "guardian", type: "address" }],
|
|
1093
|
+
outputs: [{ name: "", type: "bool" }]
|
|
962
1094
|
},
|
|
1095
|
+
// Guardian review vote — 3 args, no slashBps. Selector 0x3ad95b6d.
|
|
1096
|
+
// GuardianVoteType: None=0, Approve=1, Block=2 (uint8).
|
|
963
1097
|
{
|
|
964
|
-
name: "
|
|
1098
|
+
name: "voteOnProposal",
|
|
965
1099
|
type: "function",
|
|
966
1100
|
stateMutability: "nonpayable",
|
|
967
|
-
inputs: [
|
|
1101
|
+
inputs: [
|
|
1102
|
+
{ name: "governor", type: "address" },
|
|
1103
|
+
{ name: "proposalId", type: "uint256" },
|
|
1104
|
+
{ name: "support", type: "uint8" }
|
|
1105
|
+
],
|
|
968
1106
|
outputs: []
|
|
969
1107
|
},
|
|
1108
|
+
// Cached review flags. Returns THREE bools (opened, resolved, blocked).
|
|
1109
|
+
// A fourth output is the SHE-88 arity break: viem refuses the 96-byte returndata.
|
|
970
1110
|
{
|
|
971
|
-
name: "
|
|
1111
|
+
name: "getReviewState",
|
|
972
1112
|
type: "function",
|
|
973
|
-
stateMutability: "
|
|
974
|
-
inputs: [
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1113
|
+
stateMutability: "view",
|
|
1114
|
+
inputs: [
|
|
1115
|
+
{ name: "governor", type: "address" },
|
|
1116
|
+
{ name: "proposalId", type: "uint256" }
|
|
1117
|
+
],
|
|
1118
|
+
outputs: [
|
|
1119
|
+
{ name: "opened", type: "bool" },
|
|
1120
|
+
{ name: "resolved", type: "bool" },
|
|
1121
|
+
{ name: "blocked", type: "bool" }
|
|
1122
|
+
]
|
|
1123
|
+
}
|
|
1124
|
+
];
|
|
1125
|
+
var STAKED_WOOD_ABI = [
|
|
978
1126
|
{
|
|
979
|
-
name: "
|
|
1127
|
+
name: "stakeAsGuardian",
|
|
980
1128
|
type: "function",
|
|
981
1129
|
stateMutability: "nonpayable",
|
|
982
|
-
inputs: [
|
|
1130
|
+
inputs: [
|
|
1131
|
+
{ name: "amount", type: "uint256" },
|
|
1132
|
+
{ name: "agentId", type: "uint256" }
|
|
1133
|
+
],
|
|
983
1134
|
outputs: []
|
|
984
|
-
},
|
|
985
|
-
// Reads
|
|
986
|
-
{
|
|
987
|
-
name: "guardianStake",
|
|
988
|
-
type: "function",
|
|
989
|
-
stateMutability: "view",
|
|
990
|
-
inputs: [{ name: "guardian", type: "address" }],
|
|
991
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
992
|
-
},
|
|
993
|
-
{
|
|
994
|
-
name: "isActiveGuardian",
|
|
995
|
-
type: "function",
|
|
996
|
-
stateMutability: "view",
|
|
997
|
-
inputs: [{ name: "guardian", type: "address" }],
|
|
998
|
-
outputs: [{ name: "", type: "bool" }]
|
|
999
1135
|
}
|
|
1000
1136
|
];
|
|
1001
1137
|
var ERC20_ABI2 = [
|
|
@@ -1127,6 +1263,17 @@ var STRATEGY_FACTORY_ABI = [
|
|
|
1127
1263
|
// ../sdk/dist/addresses.js
|
|
1128
1264
|
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1129
1265
|
var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
1266
|
+
var NO_GUARDIAN_ERA = {
|
|
1267
|
+
governorBeacon: ZERO_ADDRESS,
|
|
1268
|
+
protocolConfig: ZERO_ADDRESS,
|
|
1269
|
+
priceRouter: ZERO_ADDRESS,
|
|
1270
|
+
tierRegistry: ZERO_ADDRESS,
|
|
1271
|
+
callSandboxImpl: ZERO_ADDRESS,
|
|
1272
|
+
exposureLedger: ZERO_ADDRESS,
|
|
1273
|
+
proposerBondEscrow: ZERO_ADDRESS,
|
|
1274
|
+
challengeGame: ZERO_ADDRESS,
|
|
1275
|
+
tokenCourt: ZERO_ADDRESS
|
|
1276
|
+
};
|
|
1130
1277
|
var BASE_EAS = {
|
|
1131
1278
|
chainId: CHAIN_IDS.BASE,
|
|
1132
1279
|
address: "0x4200000000000000000000000000000000000021",
|
|
@@ -1147,11 +1294,15 @@ var BASE = {
|
|
|
1147
1294
|
sherwood: {
|
|
1148
1295
|
factory: "0xAC74EC56858d7F1f7618c8e77F65Fc26aDf33c82",
|
|
1149
1296
|
guardianRegistry: "0x49E4163b5e4b23F8f3d469Cf6fa197FB6b06A26E",
|
|
1297
|
+
stakedWood: ZERO_ADDRESS,
|
|
1298
|
+
// not in chains/8453.json
|
|
1150
1299
|
vaultImpl: "0xfce4bcE08E9C047E4736f75C2B8557e2754Ce36A",
|
|
1151
1300
|
batchExecutorLib: "0xbC79FbD5036C1Cc4A9d10BDf8628BF09a558496E",
|
|
1152
1301
|
// Not yet deployed on Base — fill in `STRATEGY_FACTORY` from
|
|
1153
1302
|
// contracts/chains/8453.json when it lands (issue #387).
|
|
1154
|
-
strategyFactory: ZERO_ADDRESS
|
|
1303
|
+
strategyFactory: ZERO_ADDRESS,
|
|
1304
|
+
// None of the guardian-era contracts are in chains/8453.json yet.
|
|
1305
|
+
...NO_GUARDIAN_ERA
|
|
1155
1306
|
},
|
|
1156
1307
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
1157
1308
|
eas: BASE_EAS,
|
|
@@ -1177,9 +1328,13 @@ var HYPEREVM = {
|
|
|
1177
1328
|
sherwood: {
|
|
1178
1329
|
factory: "0xd05Ae0E8bcf13075C29817c805d6Cc14F214393a",
|
|
1179
1330
|
guardianRegistry: "0x8b5710EB4e2fA639F364Dcc3F3B30c8f12F460b9",
|
|
1331
|
+
stakedWood: ZERO_ADDRESS,
|
|
1332
|
+
// no known sWOOD deployment
|
|
1180
1333
|
vaultImpl: "0x2cbBe36Cf907A2BB410bacB0e4Fd632C7b012846",
|
|
1181
1334
|
batchExecutorLib: "0x2c454bEF1b09c8a306a7058b8B510bF0DfF7179D",
|
|
1182
|
-
strategyFactory: ZERO_ADDRESS
|
|
1335
|
+
strategyFactory: ZERO_ADDRESS,
|
|
1336
|
+
// No canonical chain book for HyperEVM — guardian-era contracts unknown.
|
|
1337
|
+
...NO_GUARDIAN_ERA
|
|
1183
1338
|
},
|
|
1184
1339
|
// ERC-8004 identity is minted on Base; HyperEVM funds reference the
|
|
1185
1340
|
// Base-minted token id. Coordination attestations are pinned to Base EAS.
|
|
@@ -1202,9 +1357,13 @@ var ROBINHOOD = {
|
|
|
1202
1357
|
sherwood: {
|
|
1203
1358
|
factory: ZERO_ADDRESS,
|
|
1204
1359
|
guardianRegistry: ZERO_ADDRESS,
|
|
1360
|
+
stakedWood: ZERO_ADDRESS,
|
|
1361
|
+
// 4663.json has WOOD, no STAKED_WOOD
|
|
1205
1362
|
vaultImpl: ZERO_ADDRESS,
|
|
1206
1363
|
batchExecutorLib: ZERO_ADDRESS,
|
|
1207
|
-
strategyFactory: ZERO_ADDRESS
|
|
1364
|
+
strategyFactory: ZERO_ADDRESS,
|
|
1365
|
+
// Sherwood not deployed on Robinhood mainnet — no guardian-era contracts.
|
|
1366
|
+
...NO_GUARDIAN_ERA
|
|
1208
1367
|
},
|
|
1209
1368
|
// No ERC-8004 registry and no EAS path on Robinhood Chain.
|
|
1210
1369
|
identityRegistry: ZERO_ADDRESS,
|
|
@@ -1233,14 +1392,32 @@ var ROBINHOOD_L2 = {
|
|
|
1233
1392
|
sherwood: {
|
|
1234
1393
|
factory: "0xa91AA45AFF32f52b6357044B02a16EBA775feC0b",
|
|
1235
1394
|
guardianRegistry: "0xA400eFcfFc820C6f812203C58ee00423AeCC0903",
|
|
1395
|
+
stakedWood: "0x21A69A6c9814c0d339C57fDdafed3B283702a739",
|
|
1236
1396
|
vaultImpl: "0xC57e12d6e2d8Ed49316F0b69c51893CcA44151F7",
|
|
1237
1397
|
batchExecutorLib: "0xF3b8db5aa41c7Ce92478A0Fa9C55a6460533eb86",
|
|
1238
|
-
strategyFactory: "0xb683Bb8EEcBc2419BC3801df6FeA88f96657e670"
|
|
1398
|
+
strategyFactory: "0xb683Bb8EEcBc2419BC3801df6FeA88f96657e670",
|
|
1399
|
+
// Guardian-era contracts from contracts/chains/46630.json (SHE-93).
|
|
1400
|
+
governorBeacon: "0x3D46Ec018cd5893b685b4dfdc3921A4Eb64E11d1",
|
|
1401
|
+
protocolConfig: "0xC104Eb6a522d6718cA28F344B2373B29d57FF2E0",
|
|
1402
|
+
priceRouter: "0xDd302ffcfA08071780eC1A2f12BccFB9ba6b6731",
|
|
1403
|
+
tierRegistry: "0x99b8068Dc0F6093466964D581f72d947e3e380DB",
|
|
1404
|
+
callSandboxImpl: "0xf09f6AF7DeBB964eD731376C9Af389F2Ce3d872A",
|
|
1405
|
+
// Not in chains/46630.json (econ-security stack not deployed there yet).
|
|
1406
|
+
exposureLedger: ZERO_ADDRESS,
|
|
1407
|
+
proposerBondEscrow: ZERO_ADDRESS,
|
|
1408
|
+
challengeGame: ZERO_ADDRESS,
|
|
1409
|
+
tokenCourt: ZERO_ADDRESS
|
|
1239
1410
|
},
|
|
1240
1411
|
// No ERC-8004 registry and no EAS path on Robinhood L2.
|
|
1241
1412
|
identityRegistry: ZERO_ADDRESS,
|
|
1242
1413
|
eas: NO_EAS,
|
|
1243
|
-
tokens: {
|
|
1414
|
+
tokens: {
|
|
1415
|
+
wood: {
|
|
1416
|
+
address: "0xCCb4fB59cf40de1E23083037ee81Da1DD747D8d7",
|
|
1417
|
+
symbol: "WOOD",
|
|
1418
|
+
decimals: 18
|
|
1419
|
+
}
|
|
1420
|
+
},
|
|
1244
1421
|
explorer: "https://explorer.testnet.chain.robinhood.com",
|
|
1245
1422
|
rpcs: ["https://rpc.testnet.chain.robinhood.com"]
|
|
1246
1423
|
};
|
|
@@ -1251,9 +1428,21 @@ var ROBINHOOD_FORK = {
|
|
|
1251
1428
|
sherwood: {
|
|
1252
1429
|
factory: "0x02bc9B9C1A4322D5A5df86DadA0a2a02e45108B9",
|
|
1253
1430
|
guardianRegistry: "0xdfEe38C4D7595c9c04AdBcaFE01E4Fd6FD6117f4",
|
|
1431
|
+
stakedWood: "0xD3037D28693cc7BB3DbF1E17B6e01C4ce628f6DF",
|
|
1254
1432
|
vaultImpl: "0x9BF51da59B13746e6cCeb1b35c398EDA9776a4Dc",
|
|
1255
1433
|
batchExecutorLib: "0xdBdBce2af4222Abe0cCDAc05f84364a50577B5a2",
|
|
1256
|
-
strategyFactory: "0xb3C009aECAeDd5ccC62Ec12eDAAA55F19C4A1eFb"
|
|
1434
|
+
strategyFactory: "0xb3C009aECAeDd5ccC62Ec12eDAAA55F19C4A1eFb",
|
|
1435
|
+
// Guardian-era contracts from sherwood-protocol/chains/9994663.json (SHE-93).
|
|
1436
|
+
governorBeacon: "0x2e8aB422Db9127F1a70d8C38A15903f22B51DA97",
|
|
1437
|
+
protocolConfig: "0x36C45dC52FbC267d8536E8456ADe5255eC83A5ab",
|
|
1438
|
+
// Not in chains/9994663.json (no PriceRouter / CallSandbox on the fork).
|
|
1439
|
+
priceRouter: ZERO_ADDRESS,
|
|
1440
|
+
tierRegistry: "0x42B089B816F994d792481fAa308199E9CF63be9f",
|
|
1441
|
+
callSandboxImpl: ZERO_ADDRESS,
|
|
1442
|
+
exposureLedger: "0x223e2Fd41aD6487333146fc3998d000E74CB1549",
|
|
1443
|
+
proposerBondEscrow: "0xef2D6994faCad11e6CfAF3DaBf7b0B2091009B05",
|
|
1444
|
+
challengeGame: "0x202c1F133006D6706e872433CCAfD729c7A8AE56",
|
|
1445
|
+
tokenCourt: "0x5DC603881f5d77f41bbd4202F1d518263Dfd497f"
|
|
1257
1446
|
},
|
|
1258
1447
|
// No ERC-8004 registry and no EAS path on the Robinhood fork.
|
|
1259
1448
|
identityRegistry: ZERO_ADDRESS,
|
|
@@ -1263,6 +1452,11 @@ var ROBINHOOD_FORK = {
|
|
|
1263
1452
|
address: "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
1264
1453
|
symbol: "WETH",
|
|
1265
1454
|
decimals: 18
|
|
1455
|
+
},
|
|
1456
|
+
wood: {
|
|
1457
|
+
address: "0xF8BC08092C06dB6148114DCf82AF881F1085f92b",
|
|
1458
|
+
symbol: "WOOD",
|
|
1459
|
+
decimals: 18
|
|
1266
1460
|
}
|
|
1267
1461
|
},
|
|
1268
1462
|
// A Tenderly vnet scopes its blocks under /explorer/vnet/<id> — the bare
|
|
@@ -1689,6 +1883,155 @@ function encodePropose(args, chainId) {
|
|
|
1689
1883
|
note: "Reverts if the vault has an active proposal (cooldown not elapsed). The strategy address is immutable post-propose; pass address(0) to opt out of live NAV. `coProposers[].splitBps` total must satisfy contract-side constraints."
|
|
1690
1884
|
};
|
|
1691
1885
|
}
|
|
1886
|
+
var MAX_SANDBOX_CALLS = 32;
|
|
1887
|
+
var MAX_SANDBOX_TOKENS = 16;
|
|
1888
|
+
function validateSandboxCall(call, idx) {
|
|
1889
|
+
if (!call || typeof call !== "object") {
|
|
1890
|
+
throw usage(`\`sandbox.calls[${idx}]\` must be an object of {target, data}`);
|
|
1891
|
+
}
|
|
1892
|
+
const c = call;
|
|
1893
|
+
if ("value" in c && c.value !== void 0 && c.value !== null) {
|
|
1894
|
+
throw usage(`\`sandbox.calls[${idx}]\` must be (address,bytes) only \u2014 ICallSandbox.Call has no \`value\` field (native value would open an unmetered transfer channel). Do not alias BatchExecutorLib.Call.`);
|
|
1895
|
+
}
|
|
1896
|
+
if (typeof c.target !== "string" || !isAddress(c.target)) {
|
|
1897
|
+
throw usage(`\`sandbox.calls[${idx}].target\` must be a 0x-prefixed address`);
|
|
1898
|
+
}
|
|
1899
|
+
if (getAddress2(c.target) === ZERO_ADDRESS2) {
|
|
1900
|
+
throw usage(`\`sandbox.calls[${idx}].target\` must not be the zero address (the governor reverts ZeroSandboxTarget)`);
|
|
1901
|
+
}
|
|
1902
|
+
if (typeof c.data !== "string" || !/^0x[0-9a-fA-F]*$/.test(c.data)) {
|
|
1903
|
+
throw usage(`\`sandbox.calls[${idx}].data\` must be a 0x-prefixed hex string`);
|
|
1904
|
+
}
|
|
1905
|
+
return { target: getAddress2(c.target), data: c.data };
|
|
1906
|
+
}
|
|
1907
|
+
function validateSandboxPayload(sandbox, maxCapital) {
|
|
1908
|
+
if (!sandbox || typeof sandbox !== "object") {
|
|
1909
|
+
throw usage("`sandbox` must be an object of {funding, calls, declaredTokens}");
|
|
1910
|
+
}
|
|
1911
|
+
const s = sandbox;
|
|
1912
|
+
const funding = toBigInt(s.funding, "sandbox.funding");
|
|
1913
|
+
if (funding === 0n) {
|
|
1914
|
+
throw usage("`sandbox.funding` must be > 0 (the governor rejects zero as ZeroSandboxFunding)");
|
|
1915
|
+
}
|
|
1916
|
+
if (funding > maxCapital) {
|
|
1917
|
+
throw usage(`\`sandbox.funding\` (${funding}) exceeds \`envelope.maxCapital\` (${maxCapital}) \u2014 the sandbox is funded out of the declared envelope, not beside it`);
|
|
1918
|
+
}
|
|
1919
|
+
if (!Array.isArray(s.calls)) {
|
|
1920
|
+
throw usage("`sandbox.calls` must be an array of {target, data} objects (no value)");
|
|
1921
|
+
}
|
|
1922
|
+
if (s.calls.length === 0) {
|
|
1923
|
+
throw usage("`sandbox.calls` must be non-empty (the governor rejects empty as EmptySandboxCalls)");
|
|
1924
|
+
}
|
|
1925
|
+
if (s.calls.length > MAX_SANDBOX_CALLS) {
|
|
1926
|
+
throw usage(`\`sandbox.calls\` has ${s.calls.length} entries; max is ${MAX_SANDBOX_CALLS}`);
|
|
1927
|
+
}
|
|
1928
|
+
const calls = s.calls.map((c, i) => validateSandboxCall(c, i));
|
|
1929
|
+
const rawTokens = s.declaredTokens ?? [];
|
|
1930
|
+
if (!Array.isArray(rawTokens)) {
|
|
1931
|
+
throw usage("`sandbox.declaredTokens` must be an array of addresses");
|
|
1932
|
+
}
|
|
1933
|
+
if (rawTokens.length > MAX_SANDBOX_TOKENS) {
|
|
1934
|
+
throw usage(`\`sandbox.declaredTokens\` has ${rawTokens.length} entries; max is ${MAX_SANDBOX_TOKENS}`);
|
|
1935
|
+
}
|
|
1936
|
+
const declaredTokens = [];
|
|
1937
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1938
|
+
for (let i = 0; i < rawTokens.length; i++) {
|
|
1939
|
+
const t = rawTokens[i];
|
|
1940
|
+
if (typeof t !== "string" || !isAddress(t)) {
|
|
1941
|
+
throw usage(`\`sandbox.declaredTokens[${i}]\` must be a 0x-prefixed address`);
|
|
1942
|
+
}
|
|
1943
|
+
const addr = getAddress2(t);
|
|
1944
|
+
if (seen.has(addr.toLowerCase())) {
|
|
1945
|
+
throw usage(`\`sandbox.declaredTokens[${i}]\` duplicates ${addr} (the governor reverts DuplicateSandboxToken)`);
|
|
1946
|
+
}
|
|
1947
|
+
seen.add(addr.toLowerCase());
|
|
1948
|
+
declaredTokens.push(addr);
|
|
1949
|
+
}
|
|
1950
|
+
return { funding, calls, declaredTokens };
|
|
1951
|
+
}
|
|
1952
|
+
function encodeProposeWithSandbox(args, chainId) {
|
|
1953
|
+
const vault = getAddress2(args.vault);
|
|
1954
|
+
const governor = parseGovernor(args.governor);
|
|
1955
|
+
const strategy2 = args.strategy === ZERO_ADDRESS2 ? ZERO_ADDRESS2 : getAddress2(args.strategy);
|
|
1956
|
+
if (typeof args.metadataURI !== "string" || args.metadataURI.length === 0) {
|
|
1957
|
+
throw usage("`metadataURI` must be a non-empty string (e.g. ipfs://...)");
|
|
1958
|
+
}
|
|
1959
|
+
const strategyDuration = typeof args.strategyDuration === "bigint" ? args.strategyDuration : BigInt(args.strategyDuration);
|
|
1960
|
+
if (strategyDuration <= 0n) {
|
|
1961
|
+
throw usage("`strategyDuration` must be > 0 (seconds)");
|
|
1962
|
+
}
|
|
1963
|
+
if (!Array.isArray(args.executeCalls)) {
|
|
1964
|
+
throw usage("`executeCalls` must be an array of {target, data, value} objects");
|
|
1965
|
+
}
|
|
1966
|
+
if (!Array.isArray(args.settlementCalls)) {
|
|
1967
|
+
throw usage("`settlementCalls` must be an array of {target, data, value} objects");
|
|
1968
|
+
}
|
|
1969
|
+
const executeCalls = args.executeCalls.map((c, i) => validateBatchCall(c, "executeCalls", i));
|
|
1970
|
+
const settlementCalls = args.settlementCalls.map((c, i) => validateBatchCall(c, "settlementCalls", i));
|
|
1971
|
+
const coProposers = (args.coProposers ?? []).map((cp, i) => {
|
|
1972
|
+
if (!cp || typeof cp !== "object") {
|
|
1973
|
+
throw usage(`\`coProposers[${i}]\` must be an object`);
|
|
1974
|
+
}
|
|
1975
|
+
const agent = cp.agent;
|
|
1976
|
+
const splitBps = cp.splitBps;
|
|
1977
|
+
if (typeof agent !== "string" || !isAddress(agent)) {
|
|
1978
|
+
throw usage(`\`coProposers[${i}].agent\` must be a 0x-prefixed address`);
|
|
1979
|
+
}
|
|
1980
|
+
let bps;
|
|
1981
|
+
if (typeof splitBps === "string" && /^\d+$/.test(splitBps)) {
|
|
1982
|
+
bps = BigInt(splitBps);
|
|
1983
|
+
} else if (typeof splitBps === "bigint") {
|
|
1984
|
+
bps = splitBps;
|
|
1985
|
+
} else if (typeof splitBps === "number" && Number.isInteger(splitBps) && splitBps >= 0) {
|
|
1986
|
+
bps = BigInt(splitBps);
|
|
1987
|
+
} else {
|
|
1988
|
+
throw usage(`\`coProposers[${i}].splitBps\` must be a non-negative integer (string, number, or bigint)`);
|
|
1989
|
+
}
|
|
1990
|
+
if (bps < 0n || bps > 10000n) {
|
|
1991
|
+
throw usage(`\`coProposers[${i}].splitBps\` must be in [0, 10000]`);
|
|
1992
|
+
}
|
|
1993
|
+
return { agent: getAddress2(agent), splitBps: bps };
|
|
1994
|
+
});
|
|
1995
|
+
if (!args.envelope || typeof args.envelope !== "object") {
|
|
1996
|
+
throw usage("`envelope` must be an object of {maxCapital, maxDrawdownBps}");
|
|
1997
|
+
}
|
|
1998
|
+
const maxCapital = toBigInt(args.envelope.maxCapital, "envelope.maxCapital");
|
|
1999
|
+
if (maxCapital === 0n) {
|
|
2000
|
+
throw usage("`envelope.maxCapital` must be > 0 (the governor rejects zero as ZeroMaxCapital)");
|
|
2001
|
+
}
|
|
2002
|
+
const maxDrawdownBps = args.envelope.maxDrawdownBps;
|
|
2003
|
+
if (!Number.isInteger(maxDrawdownBps) || maxDrawdownBps < 0 || maxDrawdownBps > 1e4) {
|
|
2004
|
+
throw usage("`envelope.maxDrawdownBps` must be an integer in [0, 10000]");
|
|
2005
|
+
}
|
|
2006
|
+
const executeCallCaps = validateCaps(args.executeCallCaps, executeCalls, maxCapital, "executeCallCaps");
|
|
2007
|
+
const settlementCallCaps = validateCaps(args.settlementCallCaps, settlementCalls, maxCapital, "settlementCallCaps");
|
|
2008
|
+
const sandbox = validateSandboxPayload(args.sandbox, maxCapital);
|
|
2009
|
+
const data = encodeFunctionData2({
|
|
2010
|
+
abi: SYNDICATE_GOVERNOR_ABI,
|
|
2011
|
+
functionName: "proposeWithSandbox",
|
|
2012
|
+
args: [
|
|
2013
|
+
sandbox,
|
|
2014
|
+
vault,
|
|
2015
|
+
strategy2,
|
|
2016
|
+
args.metadataURI,
|
|
2017
|
+
strategyDuration,
|
|
2018
|
+
{ maxCapital, maxDrawdownBps },
|
|
2019
|
+
executeCalls,
|
|
2020
|
+
executeCallCaps,
|
|
2021
|
+
settlementCalls,
|
|
2022
|
+
settlementCallCaps,
|
|
2023
|
+
coProposers
|
|
2024
|
+
]
|
|
2025
|
+
});
|
|
2026
|
+
return {
|
|
2027
|
+
txs: [governorTx(governor, chainId, data)],
|
|
2028
|
+
preconditions: [
|
|
2029
|
+
{ type: "vault-not-locked", vault }
|
|
2030
|
+
],
|
|
2031
|
+
description: `Propose a sandbox strategy on ${vault} (funding ${sandbox.funding.toString()}, ${sandbox.calls.length} sandbox call(s), duration ${strategyDuration.toString()}s).`,
|
|
2032
|
+
note: "Reverts if the vault has an active proposal, has no CallSandbox implementation bound, or the payload fails propose-time sandbox gates (empty calls, zero funding, funding > maxCapital, zero target, duplicate declared tokens). ICallSandbox.Call is (address,bytes) only \u2014 no native value."
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
1692
2035
|
function encodeUnstick(args, chainId) {
|
|
1693
2036
|
const governor = parseGovernor(args.governor);
|
|
1694
2037
|
const id = parseProposalId(args.proposalId);
|
|
@@ -2057,6 +2400,13 @@ function encodeApproveAgent(args, chainId) {
|
|
|
2057
2400
|
// ../sdk/dist/encoders/guardian.js
|
|
2058
2401
|
import { encodeFunctionData as encodeFunctionData7, getAddress as getAddress7 } from "viem";
|
|
2059
2402
|
var ZERO_VALUE5 = "0x0";
|
|
2403
|
+
function swoodTx(chainId, data) {
|
|
2404
|
+
const swood2 = getDeployment(chainId).sherwood.stakedWood;
|
|
2405
|
+
if (swood2 === "0x0000000000000000000000000000000000000000") {
|
|
2406
|
+
throw unsupported(`sWOOD (StakedWood) is not deployed on chain ${chainId} yet`);
|
|
2407
|
+
}
|
|
2408
|
+
return { to: swood2, data, value: ZERO_VALUE5, chainId };
|
|
2409
|
+
}
|
|
2060
2410
|
function registryTx(chainId, data) {
|
|
2061
2411
|
const registry = getDeployment(chainId).sherwood.guardianRegistry;
|
|
2062
2412
|
if (registry === "0x0000000000000000000000000000000000000000") {
|
|
@@ -2086,26 +2436,31 @@ function encodeGuardianStake(args, chainId) {
|
|
|
2086
2436
|
throw usage("`amount` must be > 0");
|
|
2087
2437
|
const agentId = parseUint(args.agentId, "agentId");
|
|
2088
2438
|
const data = encodeFunctionData7({
|
|
2089
|
-
abi:
|
|
2439
|
+
abi: STAKED_WOOD_ABI,
|
|
2090
2440
|
functionName: "stakeAsGuardian",
|
|
2091
2441
|
args: [args.amount, agentId]
|
|
2092
2442
|
});
|
|
2093
|
-
const
|
|
2443
|
+
const deployment = getDeployment(chainId);
|
|
2444
|
+
const wood2 = deployment.tokens.wood?.address;
|
|
2445
|
+
const swood2 = deployment.sherwood.stakedWood;
|
|
2446
|
+
if (!wood2 || wood2 === "0x0000000000000000000000000000000000000000" || swood2 === "0x0000000000000000000000000000000000000000") {
|
|
2447
|
+
throw unsupported(`WOOD / sWOOD is not deployed on chain ${chainId} yet`);
|
|
2448
|
+
}
|
|
2094
2449
|
return {
|
|
2095
|
-
txs: [
|
|
2450
|
+
txs: [swoodTx(chainId, data)],
|
|
2096
2451
|
preconditions: [
|
|
2097
|
-
// Caller must have approved WOOD for
|
|
2452
|
+
// Caller must have approved WOOD for sWOOD (StakedWood); agent should
|
|
2098
2453
|
// check this client-side and prepend an ERC20.approve if needed.
|
|
2099
2454
|
{
|
|
2100
2455
|
type: "allowance",
|
|
2101
|
-
token:
|
|
2102
|
-
spender:
|
|
2456
|
+
token: wood2,
|
|
2457
|
+
spender: swood2,
|
|
2103
2458
|
min: args.amount.toString(),
|
|
2104
2459
|
minDecimal: args.amount.toString()
|
|
2105
2460
|
}
|
|
2106
2461
|
],
|
|
2107
2462
|
description: `Stake ${args.amount.toString()} WOOD as guardian (agent ${agentId.toString()}).`,
|
|
2108
|
-
note: "Caller must have approved WOOD for
|
|
2463
|
+
note: "Caller must have approved WOOD for sWOOD (StakedWood) first. Stake locks the WOOD; use /prepare/guardian-unstake later to start the 7d unstake cooldown."
|
|
2109
2464
|
};
|
|
2110
2465
|
}
|
|
2111
2466
|
var GUARDIAN_UNSTAKE_FN = {
|
|
@@ -2130,59 +2485,29 @@ function encodeGuardianUnstake(args, chainId) {
|
|
|
2130
2485
|
note: args.action === "request" ? "Starts a 7-day cooldown. After it elapses, call again with action=claim to withdraw." : args.action === "claim" ? "Withdraws the unstake amount once the 7-day cooldown has elapsed." : "Cancels a pending unstake request and re-activates the guardian."
|
|
2131
2486
|
};
|
|
2132
2487
|
}
|
|
2133
|
-
function
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
functionName: "delegateStake",
|
|
2140
|
-
args: [delegate, args.amount]
|
|
2141
|
-
});
|
|
2142
|
-
return {
|
|
2143
|
-
txs: [registryTx(chainId, data)],
|
|
2144
|
-
preconditions: [],
|
|
2145
|
-
description: `Delegate ${args.amount.toString()} WOOD to ${delegate}.`,
|
|
2146
|
-
note: "Caller must have approved WOOD for the registry first. Delegation does NOT activate the delegate as a guardian \u2014 they must self-stake separately."
|
|
2147
|
-
};
|
|
2148
|
-
}
|
|
2149
|
-
var DELEGATION_UNSTAKE_FN = {
|
|
2150
|
-
request: "requestUnstakeDelegation",
|
|
2151
|
-
cancel: "cancelUnstakeDelegation",
|
|
2152
|
-
claim: "claimUnstakeDelegation"
|
|
2153
|
-
};
|
|
2154
|
-
function encodeDelegationUnstake(args, chainId) {
|
|
2155
|
-
const fn = DELEGATION_UNSTAKE_FN[args.action];
|
|
2156
|
-
if (!fn) {
|
|
2157
|
-
throw usage(`\`action\` must be one of: ${Object.keys(DELEGATION_UNSTAKE_FN).join(", ")}`);
|
|
2488
|
+
function encodeVoteOnProposal(args, chainId) {
|
|
2489
|
+
let governor;
|
|
2490
|
+
try {
|
|
2491
|
+
governor = getAddress7(args.governor);
|
|
2492
|
+
} catch {
|
|
2493
|
+
throw usage("`governor` must be a 0x-prefixed 40-char hex address");
|
|
2158
2494
|
}
|
|
2159
|
-
const
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
functionName: fn,
|
|
2163
|
-
args: [delegate]
|
|
2164
|
-
});
|
|
2165
|
-
return {
|
|
2166
|
-
txs: [registryTx(chainId, data)],
|
|
2167
|
-
preconditions: [],
|
|
2168
|
-
description: `Delegation unstake ${args.action} for delegate ${delegate}.`,
|
|
2169
|
-
note: args.action === "request" ? "Starts a 7-day cooldown on the delegated amount." : args.action === "claim" ? "Withdraws the delegated amount once the 7-day cooldown has elapsed." : "Cancels a pending unstake of the delegation."
|
|
2170
|
-
};
|
|
2171
|
-
}
|
|
2172
|
-
function encodeSetCommission(args, chainId) {
|
|
2173
|
-
if (!Number.isInteger(args.bps) || args.bps < 0 || args.bps > 5e3) {
|
|
2174
|
-
throw usage("`bps` must be an integer in [0, 5000] (0\u201350%)");
|
|
2495
|
+
const support = GUARDIAN_VOTE_TYPES.indexOf(args.vote);
|
|
2496
|
+
if (support <= 0) {
|
|
2497
|
+
throw usage("`vote` must be one of: Approve, Block");
|
|
2175
2498
|
}
|
|
2499
|
+
const proposalId = parseUint(args.proposalId, "proposalId");
|
|
2176
2500
|
const data = encodeFunctionData7({
|
|
2177
2501
|
abi: GUARDIAN_REGISTRY_ABI,
|
|
2178
|
-
functionName: "
|
|
2179
|
-
args: [
|
|
2502
|
+
functionName: "voteOnProposal",
|
|
2503
|
+
args: [governor, proposalId, support]
|
|
2180
2504
|
});
|
|
2505
|
+
const underwriting = args.vote === "Approve" ? " APPROVE books coverage against the CALLER'S OWN slashable guardian bond (ExposureLedger.recordApproval). If this proposal is later challenged or slashed, your WOOD stake is at risk \u2014 not another guardian's. An over-exposed guardian books nothing rather than reverting; the vote still lands." : " Block votes do not book coverage. Slash severity is computed at resolveReview from block-side decisiveness.";
|
|
2181
2506
|
return {
|
|
2182
2507
|
txs: [registryTx(chainId, data)],
|
|
2183
2508
|
preconditions: [],
|
|
2184
|
-
description: `
|
|
2185
|
-
note:
|
|
2509
|
+
description: `Guardian review vote ${args.vote} on proposal ${proposalId.toString()} (governor ${governor}).`,
|
|
2510
|
+
note: `voteOnProposal(governor, proposalId, vote) \u2014 3 args, selector 0x3ad95b6d, no slashBps.${underwriting}`
|
|
2186
2511
|
};
|
|
2187
2512
|
}
|
|
2188
2513
|
|
|
@@ -2196,7 +2521,7 @@ var DIM = chalk.gray;
|
|
|
2196
2521
|
var BOLD = chalk.white.bold;
|
|
2197
2522
|
var LABEL = chalk.green.bold;
|
|
2198
2523
|
var SEP = () => console.log(DIM("\u2500".repeat(60)));
|
|
2199
|
-
var
|
|
2524
|
+
var STAKED_WOOD_ABI2 = [
|
|
2200
2525
|
// Guardian stake
|
|
2201
2526
|
{ type: "function", name: "stakeAsGuardian", inputs: [{ type: "uint256" }, { type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
2202
2527
|
// Owner bond (required before SyndicateFactory.createSyndicate)
|
|
@@ -2204,19 +2529,9 @@ var STAKED_WOOD_ABI = [
|
|
|
2204
2529
|
{ type: "function", name: "requestUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
2205
2530
|
{ type: "function", name: "cancelUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
2206
2531
|
{ type: "function", name: "claimUnstakeGuardian", inputs: [], outputs: [], stateMutability: "nonpayable" },
|
|
2207
|
-
// Delegation
|
|
2208
|
-
{ type: "function", name: "delegateStake", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
2209
|
-
{ type: "function", name: "requestUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
2210
|
-
{ type: "function", name: "cancelUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
2211
|
-
{ type: "function", name: "claimUnstakeDelegation", inputs: [{ type: "address" }], outputs: [], stateMutability: "nonpayable" },
|
|
2212
|
-
// Commission
|
|
2213
|
-
{ type: "function", name: "setCommission", inputs: [{ type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
|
|
2214
2532
|
// Views
|
|
2215
2533
|
{ type: "function", name: "guardianStake", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
2216
|
-
{ type: "function", name: "isActiveGuardian", inputs: [{ type: "address" }], outputs: [{ type: "bool" }], stateMutability: "view" }
|
|
2217
|
-
{ type: "function", name: "commissionOf", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
2218
|
-
{ type: "function", name: "delegationOf", inputs: [{ type: "address" }, { type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" },
|
|
2219
|
-
{ type: "function", name: "delegatedInbound", inputs: [{ type: "address" }], outputs: [{ type: "uint256" }], stateMutability: "view" }
|
|
2534
|
+
{ type: "function", name: "isActiveGuardian", inputs: [{ type: "address" }], outputs: [{ type: "bool" }], stateMutability: "view" }
|
|
2220
2535
|
];
|
|
2221
2536
|
var ERC20_ABI3 = [
|
|
2222
2537
|
{ type: "function", name: "approve", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [{ type: "bool" }], stateMutability: "nonpayable" },
|
|
@@ -2267,8 +2582,8 @@ async function ensureWoodAllowance(amount, spender, label = "WOOD") {
|
|
|
2267
2582
|
}
|
|
2268
2583
|
}
|
|
2269
2584
|
function registerGuardianCommands(program2) {
|
|
2270
|
-
const guardian = program2.command("guardian").description("Guardian staking
|
|
2271
|
-
guardian.command("status [address]").description("Show guardian stake +
|
|
2585
|
+
const guardian = program2.command("guardian").description("Guardian staking and rewards");
|
|
2586
|
+
guardian.command("status [address]").description("Show guardian stake + active status for an address (default: caller)").action(async (addressArg) => {
|
|
2272
2587
|
const pc = getPublicClient();
|
|
2273
2588
|
let target;
|
|
2274
2589
|
if (addressArg) {
|
|
@@ -2283,17 +2598,10 @@ function registerGuardianCommands(program2) {
|
|
|
2283
2598
|
}
|
|
2284
2599
|
const spinner = ora("Loading...").start();
|
|
2285
2600
|
try {
|
|
2286
|
-
const [stake, active
|
|
2287
|
-
pc.readContract({ address: swood(), abi:
|
|
2288
|
-
pc.readContract({ address: swood(), abi:
|
|
2289
|
-
pc.readContract({ address: swood(), abi: STAKED_WOOD_ABI, functionName: "commissionOf", args: [target] })
|
|
2601
|
+
const [stake, active] = await Promise.all([
|
|
2602
|
+
pc.readContract({ address: swood(), abi: STAKED_WOOD_ABI2, functionName: "guardianStake", args: [target] }),
|
|
2603
|
+
pc.readContract({ address: swood(), abi: STAKED_WOOD_ABI2, functionName: "isActiveGuardian", args: [target] })
|
|
2290
2604
|
]);
|
|
2291
|
-
const delegatedIn = await pc.readContract({
|
|
2292
|
-
address: swood(),
|
|
2293
|
-
abi: STAKED_WOOD_ABI,
|
|
2294
|
-
functionName: "delegatedInbound",
|
|
2295
|
-
args: [target]
|
|
2296
|
-
});
|
|
2297
2605
|
spinner.stop();
|
|
2298
2606
|
console.log();
|
|
2299
2607
|
console.log(LABEL(" \u25C6 Guardian Status"));
|
|
@@ -2301,8 +2609,6 @@ function registerGuardianCommands(program2) {
|
|
|
2301
2609
|
console.log(W(` Address: ${G(target)}`));
|
|
2302
2610
|
console.log(W(` Active guardian: ${active ? G("yes") : DIM("no")}`));
|
|
2303
2611
|
console.log(W(` Own stake: ${BOLD(formatUnits3(stake, 18))} WOOD`));
|
|
2304
|
-
console.log(W(` Delegated inbound: ${BOLD(formatUnits3(delegatedIn, 18))} WOOD`));
|
|
2305
|
-
console.log(W(` Commission: ${BOLD(`${Number(commission) / 100}%`)}`));
|
|
2306
2612
|
SEP();
|
|
2307
2613
|
console.log();
|
|
2308
2614
|
} catch (err) {
|
|
@@ -2339,7 +2645,7 @@ function registerGuardianCommands(program2) {
|
|
|
2339
2645
|
try {
|
|
2340
2646
|
const hash = await wallet.writeContract({
|
|
2341
2647
|
address: swood(),
|
|
2342
|
-
abi:
|
|
2648
|
+
abi: STAKED_WOOD_ABI2,
|
|
2343
2649
|
functionName: "stakeAsGuardian",
|
|
2344
2650
|
args: [amount, agentId],
|
|
2345
2651
|
chain: null,
|
|
@@ -2364,7 +2670,7 @@ function registerGuardianCommands(program2) {
|
|
|
2364
2670
|
try {
|
|
2365
2671
|
const hash = await wallet.writeContract({
|
|
2366
2672
|
address: swood(),
|
|
2367
|
-
abi:
|
|
2673
|
+
abi: STAKED_WOOD_ABI2,
|
|
2368
2674
|
functionName: "prepareOwnerStake",
|
|
2369
2675
|
args: [amount],
|
|
2370
2676
|
chain: null,
|
|
@@ -2394,7 +2700,7 @@ function registerGuardianCommands(program2) {
|
|
|
2394
2700
|
const pc = getPublicClient();
|
|
2395
2701
|
const spinner = ora(`${action}...`).start();
|
|
2396
2702
|
try {
|
|
2397
|
-
const hash = await wallet.writeContract({ address: swood(), abi:
|
|
2703
|
+
const hash = await wallet.writeContract({ address: swood(), abi: STAKED_WOOD_ABI2, functionName: fn, args: [], chain: null, account: wallet.account });
|
|
2398
2704
|
await pc.waitForTransactionReceipt({ hash });
|
|
2399
2705
|
spinner.succeed(`${action} confirmed. Tx: ${hash}`);
|
|
2400
2706
|
} catch (err) {
|
|
@@ -2403,80 +2709,6 @@ function registerGuardianCommands(program2) {
|
|
|
2403
2709
|
process.exit(1);
|
|
2404
2710
|
}
|
|
2405
2711
|
});
|
|
2406
|
-
guardian.command("delegate <delegate> <amount>").description("Delegate WOOD stake to a guardian. Amount in WOOD.").action(async (delegate, amountStr) => {
|
|
2407
|
-
if (!isAddress2(delegate)) {
|
|
2408
|
-
console.error(chalk.red("Invalid delegate address"));
|
|
2409
|
-
process.exit(1);
|
|
2410
|
-
}
|
|
2411
|
-
const amount = parseUnits(amountStr, 18);
|
|
2412
|
-
if (isCalldataOnly()) {
|
|
2413
|
-
emitCalldata(encodeGuardianDelegate({ delegate, amount }, getChain().id));
|
|
2414
|
-
return;
|
|
2415
|
-
}
|
|
2416
|
-
await ensureWoodAllowance(amount);
|
|
2417
|
-
const wallet = getWalletClient();
|
|
2418
|
-
const pc = getPublicClient();
|
|
2419
|
-
const spinner = ora(`Delegating ${amountStr} WOOD to ${delegate}...`).start();
|
|
2420
|
-
try {
|
|
2421
|
-
const hash = await wallet.writeContract({ address: swood(), abi: STAKED_WOOD_ABI, functionName: "delegateStake", args: [delegate, amount], chain: null, account: wallet.account });
|
|
2422
|
-
await pc.waitForTransactionReceipt({ hash });
|
|
2423
|
-
spinner.succeed(`Delegated. Tx: ${hash}`);
|
|
2424
|
-
} catch (err) {
|
|
2425
|
-
spinner.fail("Delegation failed");
|
|
2426
|
-
console.error(chalk.red(formatContractError(err)));
|
|
2427
|
-
process.exit(1);
|
|
2428
|
-
}
|
|
2429
|
-
});
|
|
2430
|
-
guardian.command("undelegate <delegate> <action>").description("Unstake-delegation flow: 'request' | 'cancel' | 'claim'").action(async (delegate, action) => {
|
|
2431
|
-
if (!isAddress2(delegate)) {
|
|
2432
|
-
console.error(chalk.red("Invalid delegate address"));
|
|
2433
|
-
process.exit(1);
|
|
2434
|
-
}
|
|
2435
|
-
const fn = { request: "requestUnstakeDelegation", cancel: "cancelUnstakeDelegation", claim: "claimUnstakeDelegation" }[action];
|
|
2436
|
-
if (!fn) {
|
|
2437
|
-
console.error(chalk.red(`Unknown action '${action}'. Use request | cancel | claim.`));
|
|
2438
|
-
process.exit(1);
|
|
2439
|
-
}
|
|
2440
|
-
if (isCalldataOnly()) {
|
|
2441
|
-
emitCalldata(encodeDelegationUnstake({ action, delegate }, getChain().id));
|
|
2442
|
-
return;
|
|
2443
|
-
}
|
|
2444
|
-
const wallet = getWalletClient();
|
|
2445
|
-
const pc = getPublicClient();
|
|
2446
|
-
const spinner = ora(`${action}...`).start();
|
|
2447
|
-
try {
|
|
2448
|
-
const hash = await wallet.writeContract({ address: swood(), abi: STAKED_WOOD_ABI, functionName: fn, args: [delegate], chain: null, account: wallet.account });
|
|
2449
|
-
await pc.waitForTransactionReceipt({ hash });
|
|
2450
|
-
spinner.succeed(`${action} confirmed. Tx: ${hash}`);
|
|
2451
|
-
} catch (err) {
|
|
2452
|
-
spinner.fail(`${action} failed`);
|
|
2453
|
-
console.error(chalk.red(formatContractError(err)));
|
|
2454
|
-
process.exit(1);
|
|
2455
|
-
}
|
|
2456
|
-
});
|
|
2457
|
-
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) => {
|
|
2458
|
-
const bps = BigInt(bpsStr);
|
|
2459
|
-
if (bps > 5000n) {
|
|
2460
|
-
console.error(chalk.red("Commission cannot exceed 5000 bps (50%)"));
|
|
2461
|
-
process.exit(1);
|
|
2462
|
-
}
|
|
2463
|
-
if (isCalldataOnly()) {
|
|
2464
|
-
emitCalldata(encodeSetCommission({ bps: Number(bps) }, getChain().id));
|
|
2465
|
-
return;
|
|
2466
|
-
}
|
|
2467
|
-
const wallet = getWalletClient();
|
|
2468
|
-
const pc = getPublicClient();
|
|
2469
|
-
const spinner = ora(`Setting commission to ${Number(bps) / 100}%...`).start();
|
|
2470
|
-
try {
|
|
2471
|
-
const hash = await wallet.writeContract({ address: swood(), abi: STAKED_WOOD_ABI, functionName: "setCommission", args: [bps], chain: null, account: wallet.account });
|
|
2472
|
-
await pc.waitForTransactionReceipt({ hash });
|
|
2473
|
-
spinner.succeed(`Commission set. Tx: ${hash}`);
|
|
2474
|
-
} catch (err) {
|
|
2475
|
-
spinner.fail("setCommission failed");
|
|
2476
|
-
console.error(chalk.red(formatContractError(err)));
|
|
2477
|
-
process.exit(1);
|
|
2478
|
-
}
|
|
2479
|
-
});
|
|
2480
2712
|
guardian.command("claim-wood").description("Open merkl.xyz to claim guardian WOOD rewards (block-rewards + guardian fees, off-chain distribution).").action(async () => {
|
|
2481
2713
|
const wallet = getWalletClient();
|
|
2482
2714
|
const addr = wallet.account.address;
|
|
@@ -2562,7 +2794,85 @@ function resolveTemplate(key) {
|
|
|
2562
2794
|
}
|
|
2563
2795
|
return { def, address };
|
|
2564
2796
|
}
|
|
2565
|
-
async function
|
|
2797
|
+
async function resolvePortfolioFeeTiers(opts, deps) {
|
|
2798
|
+
if (!opts.tokens || !opts.weights || !opts.amount || opts.feeTier) return {};
|
|
2799
|
+
if (UNISWAP().QUOTER_V2 === ZERO) return {};
|
|
2800
|
+
const tokens = TOKENS();
|
|
2801
|
+
const tokenSpecs = opts.tokens.split(",").map((t) => t.trim());
|
|
2802
|
+
const tokenAddrs = tokenSpecs.map((spec) => {
|
|
2803
|
+
if (isAddress3(spec)) return spec;
|
|
2804
|
+
const resolved = tokens[spec.toUpperCase()];
|
|
2805
|
+
return resolved && resolved !== ZERO ? resolved : null;
|
|
2806
|
+
});
|
|
2807
|
+
const weightsBps = opts.weights.split(",").map((w) => Number(w.trim()));
|
|
2808
|
+
if (tokenAddrs.length !== weightsBps.length) return {};
|
|
2809
|
+
if (weightsBps.some((w) => !Number.isFinite(w) || w < 0)) return {};
|
|
2810
|
+
const assetSymbol = opts.asset || defaultPortfolioAsset();
|
|
2811
|
+
let asset;
|
|
2812
|
+
let totalAmount;
|
|
2813
|
+
try {
|
|
2814
|
+
asset = resolveToken(assetSymbol);
|
|
2815
|
+
totalAmount = parseUnits2(opts.amount, assetDecimalsForSymbol(assetSymbol));
|
|
2816
|
+
} catch {
|
|
2817
|
+
return {};
|
|
2818
|
+
}
|
|
2819
|
+
const swapRouteOverrides = parseAlignedOverrides(
|
|
2820
|
+
opts.swapRoutes,
|
|
2821
|
+
tokenAddrs.length
|
|
2822
|
+
).values;
|
|
2823
|
+
console.log(chalk2.dim(" Quoting v3 fee tiers for best execution..."));
|
|
2824
|
+
const portfolioFeeTiers = [];
|
|
2825
|
+
for (let i = 0; i < tokenAddrs.length; i++) {
|
|
2826
|
+
const token = tokenAddrs[i];
|
|
2827
|
+
if (!token || swapRouteOverrides[i] || token.toLowerCase() === asset.toLowerCase()) {
|
|
2828
|
+
portfolioFeeTiers.push(null);
|
|
2829
|
+
continue;
|
|
2830
|
+
}
|
|
2831
|
+
const legAmount = totalAmount * BigInt(Math.round(weightsBps[i])) / 10000n;
|
|
2832
|
+
const best = await selectBestFeeTier(
|
|
2833
|
+
{
|
|
2834
|
+
tokenIn: asset,
|
|
2835
|
+
tokenOut: token,
|
|
2836
|
+
amountIn: legAmount > 0n ? legAmount : 1n,
|
|
2837
|
+
preferredFeeTier: DEFAULT_FEE_TIER
|
|
2838
|
+
},
|
|
2839
|
+
deps
|
|
2840
|
+
);
|
|
2841
|
+
if (!best) {
|
|
2842
|
+
console.warn(
|
|
2843
|
+
chalk2.yellow(
|
|
2844
|
+
` ${tokenSpecs[i]}: no fee tier quoted \u2014 falling back to fee ${DEFAULT_FEE_TIER}`
|
|
2845
|
+
)
|
|
2846
|
+
);
|
|
2847
|
+
portfolioFeeTiers.push(null);
|
|
2848
|
+
continue;
|
|
2849
|
+
}
|
|
2850
|
+
const others = best.quoted.filter((q) => q.feeTier !== best.feeTier).map((q) => `${q.feeTier}: ${q.amountOut}`).join(", ");
|
|
2851
|
+
console.log(
|
|
2852
|
+
chalk2.dim(
|
|
2853
|
+
` ${tokenSpecs[i]}: fee ${best.feeTier} (out ${best.amountOut}` + (others ? `; beat ${others}` : "; only tier that quoted") + `)`
|
|
2854
|
+
)
|
|
2855
|
+
);
|
|
2856
|
+
portfolioFeeTiers.push({
|
|
2857
|
+
feeTier: best.feeTier,
|
|
2858
|
+
routeDesc: `direct (fee ${best.feeTier}, best of ${best.quoted.length} quoted)`
|
|
2859
|
+
});
|
|
2860
|
+
}
|
|
2861
|
+
return { portfolioFeeTiers };
|
|
2862
|
+
}
|
|
2863
|
+
async function resolveChainInputsForTemplate(templateKey, opts, deps = {}) {
|
|
2864
|
+
if (templateKey === "portfolio") {
|
|
2865
|
+
try {
|
|
2866
|
+
return await resolvePortfolioFeeTiers(opts, deps);
|
|
2867
|
+
} catch (err) {
|
|
2868
|
+
console.warn(
|
|
2869
|
+
chalk2.yellow(
|
|
2870
|
+
` Fee-tier quoting unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 using default tier ${DEFAULT_FEE_TIER}`
|
|
2871
|
+
)
|
|
2872
|
+
);
|
|
2873
|
+
return {};
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2566
2876
|
if (templateKey === "venice-inference") {
|
|
2567
2877
|
if (!opts.amount) return {};
|
|
2568
2878
|
const assetSymbol = opts.asset || "USDC";
|
|
@@ -2837,7 +3147,7 @@ function registerStrategyProposeCommands(strategy2) {
|
|
|
2837
3147
|
process.exit(1);
|
|
2838
3148
|
}
|
|
2839
3149
|
if (!opts.agent) opts.agent = proposer;
|
|
2840
|
-
const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-
|
|
3150
|
+
const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-7QKGNHMR.js");
|
|
2841
3151
|
const strategyDuration2 = parseDuration3(opts.duration);
|
|
2842
3152
|
const chainId = getChain().id;
|
|
2843
3153
|
try {
|
|
@@ -3068,9 +3378,9 @@ function registerStrategyProposeCommands(strategy2) {
|
|
|
3068
3378
|
console.error(chalk3.red("Missing --name or --duration. Use --write-calls to skip proposal submission."));
|
|
3069
3379
|
process.exit(1);
|
|
3070
3380
|
}
|
|
3071
|
-
const { propose: propose2 } = await import("./governor-
|
|
3381
|
+
const { propose: propose2 } = await import("./governor-7QKGNHMR.js");
|
|
3072
3382
|
const { pinJSON } = await import("./ipfs-EJ7IHXCU.js");
|
|
3073
|
-
const { parseDuration: parseDuration2 } = await import("./governor-
|
|
3383
|
+
const { parseDuration: parseDuration2 } = await import("./governor-7QKGNHMR.js");
|
|
3074
3384
|
const strategyDuration = parseDuration2(opts.duration);
|
|
3075
3385
|
const metaSpinner = ora2("Pinning metadata to IPFS...").start();
|
|
3076
3386
|
let metadataURI;
|
|
@@ -3102,7 +3412,7 @@ function registerStrategyProposeCommands(strategy2) {
|
|
|
3102
3412
|
metadataURI = `data:application/json;base64,${Buffer.from(inline).toString("base64")}`;
|
|
3103
3413
|
}
|
|
3104
3414
|
try {
|
|
3105
|
-
const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-
|
|
3415
|
+
const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-UCFFOOTS.js");
|
|
3106
3416
|
const feeBps = await getAgentFeeBps2(vault);
|
|
3107
3417
|
console.log(
|
|
3108
3418
|
chalk3.yellow(
|
|
@@ -3373,7 +3683,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
3373
3683
|
let prices = [];
|
|
3374
3684
|
let priceSource = null;
|
|
3375
3685
|
try {
|
|
3376
|
-
const { getTokenPricesInAsset } = await import("./price-
|
|
3686
|
+
const { getTokenPricesInAsset } = await import("./price-SVF25X4O.js");
|
|
3377
3687
|
prices = await getTokenPricesInAsset({
|
|
3378
3688
|
tokens: allocations.map((a, i) => ({
|
|
3379
3689
|
token: a.token,
|
|
@@ -3803,10 +4113,10 @@ function registerVeniceCommands(program2) {
|
|
|
3803
4113
|
console.log(chalk5.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
|
|
3804
4114
|
console.log(chalk5.dim(" Saved to ~/.sherwood/config.json"));
|
|
3805
4115
|
try {
|
|
3806
|
-
const { createVeniceProvisionAttestation, getEasScanUrl
|
|
3807
|
-
const
|
|
3808
|
-
if (
|
|
3809
|
-
console.log(chalk5.dim(` Attested: ${
|
|
4116
|
+
const { createVeniceProvisionAttestation, getEasScanUrl } = await import("./eas-QPKX6A5A.js");
|
|
4117
|
+
const attestation = await createVeniceProvisionAttestation(account.address);
|
|
4118
|
+
if (attestation) {
|
|
4119
|
+
console.log(chalk5.dim(` Attested: ${getEasScanUrl(attestation.uid)}`));
|
|
3810
4120
|
}
|
|
3811
4121
|
} catch {
|
|
3812
4122
|
}
|
|
@@ -4159,21 +4469,21 @@ ${opts.prompt}`;
|
|
|
4159
4469
|
console.log(chalk5.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
|
|
4160
4470
|
}
|
|
4161
4471
|
try {
|
|
4162
|
-
const { createVeniceInferenceAttestation, getEasScanUrl
|
|
4472
|
+
const { createVeniceInferenceAttestation, getEasScanUrl } = await import("./eas-QPKX6A5A.js");
|
|
4163
4473
|
const { keccak256: keccak2563, toHex, isAddress: isAddr } = await import("viem");
|
|
4164
4474
|
const { getChainContracts: getChainContracts2 } = await import("./config-ZGFS4I7K.js");
|
|
4165
|
-
const { getChain: getActiveChain } = await import("./network-
|
|
4475
|
+
const { getChain: getActiveChain } = await import("./network-FEHRFDPJ.js");
|
|
4166
4476
|
const vaultRecipient = opts.vault && isAddr(opts.vault) ? opts.vault : getChainContracts2(getActiveChain().id).vault;
|
|
4167
4477
|
const promptHash = keccak2563(toHex(userContent)).slice(0, 18);
|
|
4168
|
-
const
|
|
4478
|
+
const attestation = await createVeniceInferenceAttestation(
|
|
4169
4479
|
result.model,
|
|
4170
4480
|
result.usage.promptTokens,
|
|
4171
4481
|
result.usage.completionTokens,
|
|
4172
4482
|
promptHash,
|
|
4173
4483
|
vaultRecipient
|
|
4174
4484
|
);
|
|
4175
|
-
if (
|
|
4176
|
-
console.log(chalk5.dim(`Attested: ${
|
|
4485
|
+
if (attestation) {
|
|
4486
|
+
console.log(chalk5.dim(`Attested: ${getEasScanUrl(attestation.uid)}`));
|
|
4177
4487
|
}
|
|
4178
4488
|
} catch {
|
|
4179
4489
|
}
|
|
@@ -5806,8 +6116,8 @@ function printSimulationResult(result, callType) {
|
|
|
5806
6116
|
}
|
|
5807
6117
|
async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
|
|
5808
6118
|
try {
|
|
5809
|
-
const xmtp = await import("./xmtp-
|
|
5810
|
-
const { getAccount: getAccount2 } = await import("./client-
|
|
6119
|
+
const xmtp = await import("./xmtp-S7IGTIMZ.js");
|
|
6120
|
+
const { getAccount: getAccount2 } = await import("./client-3SE632Q2.js");
|
|
5811
6121
|
const group = await xmtp.getGroup("", subdomain);
|
|
5812
6122
|
const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
|
|
5813
6123
|
const criticals = allRisks.filter((r) => r.level === "critical");
|
|
@@ -5916,6 +6226,48 @@ function parseCallsFile(path) {
|
|
|
5916
6226
|
value: BigInt(c.value || "0")
|
|
5917
6227
|
}));
|
|
5918
6228
|
}
|
|
6229
|
+
function parseSandboxCallsFile(path) {
|
|
6230
|
+
const raw = readFileSync2(path, "utf-8");
|
|
6231
|
+
const parsed = JSON.parse(raw);
|
|
6232
|
+
if (!Array.isArray(parsed)) {
|
|
6233
|
+
console.error(chalk9.red(" sandbox calls file must be a JSON array of {target, data} objects"));
|
|
6234
|
+
process.exit(1);
|
|
6235
|
+
}
|
|
6236
|
+
return parsed.map((c, i) => {
|
|
6237
|
+
if (!c || typeof c !== "object") {
|
|
6238
|
+
console.error(chalk9.red(` sandbox.calls[${i}] must be an object`));
|
|
6239
|
+
process.exit(1);
|
|
6240
|
+
}
|
|
6241
|
+
const rec = c;
|
|
6242
|
+
if (rec.value !== void 0 && rec.value !== null) {
|
|
6243
|
+
console.error(
|
|
6244
|
+
chalk9.red(
|
|
6245
|
+
` sandbox.calls[${i}] must be (address,bytes) only \u2014 ICallSandbox.Call has no value field.`
|
|
6246
|
+
)
|
|
6247
|
+
);
|
|
6248
|
+
process.exit(1);
|
|
6249
|
+
}
|
|
6250
|
+
if (typeof rec.target !== "string" || !isAddress9(rec.target)) {
|
|
6251
|
+
console.error(chalk9.red(` sandbox.calls[${i}].target must be a 0x-prefixed address`));
|
|
6252
|
+
process.exit(1);
|
|
6253
|
+
}
|
|
6254
|
+
if (typeof rec.data !== "string" || !/^0x[0-9a-fA-F]*$/.test(rec.data)) {
|
|
6255
|
+
console.error(chalk9.red(` sandbox.calls[${i}].data must be a 0x-prefixed hex string`));
|
|
6256
|
+
process.exit(1);
|
|
6257
|
+
}
|
|
6258
|
+
return { target: rec.target, data: rec.data };
|
|
6259
|
+
});
|
|
6260
|
+
}
|
|
6261
|
+
function parseSandboxTokens(list) {
|
|
6262
|
+
if (list === void 0 || list.trim().length === 0) return [];
|
|
6263
|
+
return list.split(",").map((x) => x.trim()).filter((x) => x.length > 0).map((a, i) => {
|
|
6264
|
+
if (!isAddress9(a)) {
|
|
6265
|
+
console.error(chalk9.red(` --sandbox-tokens[${i}] is not a 0x-prefixed address: ${a}`));
|
|
6266
|
+
process.exit(1);
|
|
6267
|
+
}
|
|
6268
|
+
return a;
|
|
6269
|
+
});
|
|
6270
|
+
}
|
|
5919
6271
|
var GUARDIAN_REGISTRY_ABI2 = [
|
|
5920
6272
|
{
|
|
5921
6273
|
type: "function",
|
|
@@ -5924,6 +6276,17 @@ var GUARDIAN_REGISTRY_ABI2 = [
|
|
|
5924
6276
|
outputs: [{ type: "bool" }],
|
|
5925
6277
|
stateMutability: "nonpayable"
|
|
5926
6278
|
},
|
|
6279
|
+
{
|
|
6280
|
+
// Permissionless keeper entrypoint (SHE-162): opens the guardian review
|
|
6281
|
+
// once `block.timestamp >= voteEnd`. Idempotent on-chain
|
|
6282
|
+
// (`if (r.opened || r.resolved) return;`), so keeper races are harmless.
|
|
6283
|
+
// No outputs — matches GuardianRegistry.openReview(address,uint256).
|
|
6284
|
+
type: "function",
|
|
6285
|
+
name: "openReview",
|
|
6286
|
+
inputs: [{ name: "governor", type: "address" }, { name: "proposalId", type: "uint256" }],
|
|
6287
|
+
outputs: [],
|
|
6288
|
+
stateMutability: "nonpayable"
|
|
6289
|
+
},
|
|
5927
6290
|
{
|
|
5928
6291
|
type: "function",
|
|
5929
6292
|
name: "getReviewState",
|
|
@@ -5934,8 +6297,30 @@ var GUARDIAN_REGISTRY_ABI2 = [
|
|
|
5934
6297
|
{ name: "blocked", type: "bool" }
|
|
5935
6298
|
],
|
|
5936
6299
|
stateMutability: "view"
|
|
6300
|
+
},
|
|
6301
|
+
{
|
|
6302
|
+
type: "function",
|
|
6303
|
+
name: "voteOnProposal",
|
|
6304
|
+
inputs: [
|
|
6305
|
+
{ name: "governor", type: "address" },
|
|
6306
|
+
{ name: "proposalId", type: "uint256" },
|
|
6307
|
+
{ name: "support", type: "uint8" }
|
|
6308
|
+
],
|
|
6309
|
+
outputs: [],
|
|
6310
|
+
stateMutability: "nonpayable"
|
|
5937
6311
|
}
|
|
5938
6312
|
];
|
|
6313
|
+
function parseGuardianReviewVote(raw) {
|
|
6314
|
+
const v = String(raw).trim().toLowerCase();
|
|
6315
|
+
if (v === "approve" || v === "yes") return "Approve";
|
|
6316
|
+
if (v === "block" || v === "no") return "Block";
|
|
6317
|
+
throw new Error(`Invalid support "${raw}". Use approve|block.`);
|
|
6318
|
+
}
|
|
6319
|
+
function formatUsd18(raw) {
|
|
6320
|
+
const n = Number(raw) / 1e18;
|
|
6321
|
+
if (!Number.isFinite(n)) return `${raw.toString()} (USD-18)`;
|
|
6322
|
+
return `$${n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
6323
|
+
}
|
|
5939
6324
|
function getRegistryAddress() {
|
|
5940
6325
|
const addr = SHERWOOD().GUARDIAN_REGISTRY;
|
|
5941
6326
|
if (addr === "0x0000000000000000000000000000000000000000") {
|
|
@@ -6177,6 +6562,171 @@ function registerProposalCommands(program2) {
|
|
|
6177
6562
|
process.exit(1);
|
|
6178
6563
|
}
|
|
6179
6564
|
});
|
|
6565
|
+
proposal.command("create-sandbox").description("Submit a strategy proposal with a CallSandbox payload (ICallSandbox.Call is (address,bytes) only \u2014 no value)").requiredOption("--vault <address>", "Vault address the proposal targets").requiredOption("--name <name>", "Strategy name").requiredOption("--description <text>", "Strategy rationale and risk summary").requiredOption("--duration <duration>", "Strategy duration (e.g. 7d, 24h, 3600)").requiredOption("--execute-calls <path>", "Path to JSON file with execute Call[] array").requiredOption("--settle-calls <path>", "Path to JSON file with settlement Call[] array").requiredOption(
|
|
6566
|
+
"--sandbox-calls <path>",
|
|
6567
|
+
"Path to JSON file of ICallSandbox.Call[] \u2014 [{target, data}, ...]. A value field is refused."
|
|
6568
|
+
).requiredOption(
|
|
6569
|
+
"--sandbox-funding <amount>",
|
|
6570
|
+
"Vault-asset amount the sandbox is funded with (decimals resolved from the asset). Must be > 0 and <= --max-capital."
|
|
6571
|
+
).option("--sandbox-tokens <list>", "Comma-separated declared non-asset token addresses the payload may hold").option("--strategy <address>", "Live-NAV strategy clone address (default: none \u2014 queue-only)").option(
|
|
6572
|
+
"--max-capital <amount>",
|
|
6573
|
+
"REQUIRED. Ceiling on what the execute batch may deploy, in vault-asset units."
|
|
6574
|
+
).option(
|
|
6575
|
+
"--max-drawdown-bps <bps>",
|
|
6576
|
+
"Declared loss allowance in bps of --max-capital (0-10000, default 2000 = 20%)."
|
|
6577
|
+
).option("--execute-caps <list>", "Comma-separated per-execute-call outflow caps in asset units").option("--settle-caps <list>", "Comma-separated per-settlement-call outflow caps in asset units").option("--metadata-uri <uri>", "Override \u2014 skip IPFS upload and use this URI directly").action(async (opts) => {
|
|
6578
|
+
try {
|
|
6579
|
+
const vault = opts.vault;
|
|
6580
|
+
if (!isAddress9(vault)) {
|
|
6581
|
+
console.error(chalk9.red(`Invalid vault address: ${opts.vault}`));
|
|
6582
|
+
process.exit(1);
|
|
6583
|
+
}
|
|
6584
|
+
const strategyDuration = parseDuration(opts.duration);
|
|
6585
|
+
const executeCalls = parseCallsFile(opts.executeCalls);
|
|
6586
|
+
const settleCalls = parseCallsFile(opts.settleCalls);
|
|
6587
|
+
const sandboxCalls = parseSandboxCallsFile(opts.sandboxCalls);
|
|
6588
|
+
const declaredTokens = parseSandboxTokens(opts.sandboxTokens);
|
|
6589
|
+
const ZERO_STRATEGY = "0x0000000000000000000000000000000000000000";
|
|
6590
|
+
let strategy2 = ZERO_STRATEGY;
|
|
6591
|
+
if (opts.strategy) {
|
|
6592
|
+
if (!isAddress9(opts.strategy)) {
|
|
6593
|
+
console.error(chalk9.red(`Invalid strategy address: ${opts.strategy}`));
|
|
6594
|
+
process.exit(1);
|
|
6595
|
+
}
|
|
6596
|
+
strategy2 = opts.strategy;
|
|
6597
|
+
}
|
|
6598
|
+
const envelope = await resolveRiskEnvelope(opts, vault);
|
|
6599
|
+
const asset = await getAssetAddress();
|
|
6600
|
+
const decimals = await getPublicClient().readContract({
|
|
6601
|
+
address: asset,
|
|
6602
|
+
abi: ERC20_ABI,
|
|
6603
|
+
functionName: "decimals"
|
|
6604
|
+
});
|
|
6605
|
+
const funding = parseUnits8(String(opts.sandboxFunding), decimals);
|
|
6606
|
+
const executeCallCaps = resolveCaps(
|
|
6607
|
+
opts.executeCaps,
|
|
6608
|
+
executeCalls.length,
|
|
6609
|
+
envelope.maxCapital,
|
|
6610
|
+
"--execute-caps"
|
|
6611
|
+
);
|
|
6612
|
+
const settleCallCaps = resolveCaps(
|
|
6613
|
+
opts.settleCaps,
|
|
6614
|
+
settleCalls.length,
|
|
6615
|
+
0n,
|
|
6616
|
+
"--settle-caps"
|
|
6617
|
+
);
|
|
6618
|
+
const buildAction = async (metadataURI2) => encodeProposeWithSandbox(
|
|
6619
|
+
{
|
|
6620
|
+
vault,
|
|
6621
|
+
governor: await getGovernorOf(vault),
|
|
6622
|
+
strategy: strategy2,
|
|
6623
|
+
metadataURI: metadataURI2,
|
|
6624
|
+
strategyDuration,
|
|
6625
|
+
envelope,
|
|
6626
|
+
executeCalls,
|
|
6627
|
+
executeCallCaps,
|
|
6628
|
+
settlementCalls: settleCalls,
|
|
6629
|
+
settlementCallCaps: settleCallCaps,
|
|
6630
|
+
sandbox: { funding, calls: sandboxCalls, declaredTokens }
|
|
6631
|
+
},
|
|
6632
|
+
getChain().id
|
|
6633
|
+
);
|
|
6634
|
+
if (isCalldataOnly()) {
|
|
6635
|
+
if (!opts.metadataUri) {
|
|
6636
|
+
console.error(
|
|
6637
|
+
chalk9.red(
|
|
6638
|
+
"--calldata-only requires --metadata-uri (IPFS metadata upload needs a signing wallet)"
|
|
6639
|
+
)
|
|
6640
|
+
);
|
|
6641
|
+
process.exit(1);
|
|
6642
|
+
}
|
|
6643
|
+
try {
|
|
6644
|
+
emitCalldata(await buildAction(opts.metadataUri));
|
|
6645
|
+
} catch (err) {
|
|
6646
|
+
console.error(chalk9.red(err instanceof Error ? err.message : String(err)));
|
|
6647
|
+
process.exit(1);
|
|
6648
|
+
}
|
|
6649
|
+
return;
|
|
6650
|
+
}
|
|
6651
|
+
let metadataURI = opts.metadataUri || "";
|
|
6652
|
+
if (!metadataURI) {
|
|
6653
|
+
const spinner2 = ora7({ text: W3("Uploading metadata to IPFS..."), color: "green" }).start();
|
|
6654
|
+
try {
|
|
6655
|
+
const account = getAccount();
|
|
6656
|
+
const metadata = {
|
|
6657
|
+
schema: "sherwood/proposal/v1",
|
|
6658
|
+
name: opts.name,
|
|
6659
|
+
description: opts.description,
|
|
6660
|
+
chain: getNetwork(),
|
|
6661
|
+
strategies: [],
|
|
6662
|
+
terms: {},
|
|
6663
|
+
links: {}
|
|
6664
|
+
};
|
|
6665
|
+
const proposalMeta = {
|
|
6666
|
+
...metadata,
|
|
6667
|
+
proposer: account.address,
|
|
6668
|
+
vault,
|
|
6669
|
+
strategyDuration: Number(strategyDuration),
|
|
6670
|
+
sandbox: true,
|
|
6671
|
+
createdAt: Math.floor(Date.now() / 1e3)
|
|
6672
|
+
};
|
|
6673
|
+
metadataURI = await uploadMetadata(proposalMeta);
|
|
6674
|
+
spinner2.succeed(G3(`Metadata pinned: ${DIM3(metadataURI)}`));
|
|
6675
|
+
} catch (err) {
|
|
6676
|
+
spinner2.warn(chalk9.yellow("IPFS upload failed \u2014 using inline metadata"));
|
|
6677
|
+
const json = JSON.stringify({ name: opts.name, description: opts.description, vault, sandbox: true });
|
|
6678
|
+
metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
|
|
6679
|
+
}
|
|
6680
|
+
}
|
|
6681
|
+
console.log();
|
|
6682
|
+
console.log(LABEL3(" \u25C6 Sandbox Proposal Summary"));
|
|
6683
|
+
SEP3();
|
|
6684
|
+
console.log(W3(` Name: ${BOLD3(opts.name)}`));
|
|
6685
|
+
console.log(W3(` Vault: ${G3(vault)}`));
|
|
6686
|
+
console.log(W3(` Duration: ${formatDurationShort(strategyDuration)}`));
|
|
6687
|
+
console.log(W3(` Calls: ${executeCalls.length} execute + ${settleCalls.length} settle + ${sandboxCalls.length} sandbox`));
|
|
6688
|
+
console.log(W3(` Sandbox funding: ${opts.sandboxFunding}`));
|
|
6689
|
+
console.log(W3(` Metadata: ${DIM3(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
|
|
6690
|
+
SEP3();
|
|
6691
|
+
const spinner = ora7({ text: W3("Submitting sandbox proposal..."), color: "green" }).start();
|
|
6692
|
+
let action;
|
|
6693
|
+
try {
|
|
6694
|
+
action = await buildAction(metadataURI);
|
|
6695
|
+
} catch (err) {
|
|
6696
|
+
spinner.fail(err instanceof Error ? err.message : String(err));
|
|
6697
|
+
process.exit(1);
|
|
6698
|
+
}
|
|
6699
|
+
const tx = action.txs[0];
|
|
6700
|
+
const hash = await sendTxWithRetry({
|
|
6701
|
+
account: getAccount(),
|
|
6702
|
+
chain: getChain(),
|
|
6703
|
+
to: tx.to,
|
|
6704
|
+
data: tx.data,
|
|
6705
|
+
value: 0n
|
|
6706
|
+
});
|
|
6707
|
+
const receipt = await waitForReceipt(hash);
|
|
6708
|
+
let proposalId = parseProposalIdFromLogs(receipt.logs);
|
|
6709
|
+
if (proposalId === void 0) {
|
|
6710
|
+
try {
|
|
6711
|
+
proposalId = await proposalCount(vault);
|
|
6712
|
+
} catch {
|
|
6713
|
+
proposalId = 0n;
|
|
6714
|
+
}
|
|
6715
|
+
}
|
|
6716
|
+
spinner.succeed(G3("Sandbox proposal submitted"));
|
|
6717
|
+
console.log();
|
|
6718
|
+
console.log(LABEL3(" \u25C6 Sandbox Proposal Created"));
|
|
6719
|
+
SEP3();
|
|
6720
|
+
console.log(W3(` Proposal ID: ${G3(`#${proposalId}`)}`));
|
|
6721
|
+
console.log(W3(` Tx: ${DIM3(getExplorerUrl(receipt.transactionHash))}`));
|
|
6722
|
+
SEP3();
|
|
6723
|
+
console.log();
|
|
6724
|
+
} catch (err) {
|
|
6725
|
+
console.error(chalk9.red(`
|
|
6726
|
+
\u2716 ${formatContractError(err)}`));
|
|
6727
|
+
process.exit(1);
|
|
6728
|
+
}
|
|
6729
|
+
});
|
|
6180
6730
|
proposal.command("list").description("List a vault's proposals (per-vault governor \u2014 IDs are scoped to the vault)").requiredOption("--vault <address>", "Vault whose proposals to list").option("--state <filter>", "Filter by state: draft, pending, approved, executed, settled, all", "all").action(async (opts) => {
|
|
6181
6731
|
const spinner = ora7("Loading proposals...").start();
|
|
6182
6732
|
try {
|
|
@@ -6365,6 +6915,112 @@ function registerProposalCommands(program2) {
|
|
|
6365
6915
|
process.exit(1);
|
|
6366
6916
|
}
|
|
6367
6917
|
});
|
|
6918
|
+
proposal.command("review-vote").description("Cast a guardian review vote (Approve or Block) on a live review").requiredOption("--id <proposalId>", "Proposal ID").requiredOption("--vault <address>", "Vault the proposal belongs to (per-vault governor)").requiredOption("--support <approve|block>", "Guardian review vote: approve or block").action(async (opts) => {
|
|
6919
|
+
try {
|
|
6920
|
+
const proposalId = parseBigIntArg(opts.id, "proposal ID");
|
|
6921
|
+
const vault = parseVaultOption(opts.vault);
|
|
6922
|
+
const vote2 = parseGuardianReviewVote(String(opts.support));
|
|
6923
|
+
const chainId = getChain().id;
|
|
6924
|
+
const governor = await getGovernorOf(vault);
|
|
6925
|
+
if (isCalldataOnly()) {
|
|
6926
|
+
emitCalldata(encodeVoteOnProposal({ governor, proposalId, vote: vote2 }, chainId));
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
const account = getAccount();
|
|
6930
|
+
const spinner = ora7("Loading review...").start();
|
|
6931
|
+
const registryAddr = getRegistryAddress();
|
|
6932
|
+
const pc = getPublicClient();
|
|
6933
|
+
const [p, state, reviewState] = await Promise.all([
|
|
6934
|
+
getProposal(vault, proposalId),
|
|
6935
|
+
getProposalState(vault, proposalId),
|
|
6936
|
+
pc.readContract({
|
|
6937
|
+
address: registryAddr,
|
|
6938
|
+
abi: GUARDIAN_REGISTRY_ABI2,
|
|
6939
|
+
functionName: "getReviewState",
|
|
6940
|
+
args: [governor, proposalId]
|
|
6941
|
+
})
|
|
6942
|
+
]);
|
|
6943
|
+
const [opened, resolved] = reviewState;
|
|
6944
|
+
const now = (await pc.getBlock()).timestamp;
|
|
6945
|
+
spinner.stop();
|
|
6946
|
+
if (!opened) {
|
|
6947
|
+
console.error(chalk9.red(
|
|
6948
|
+
`No live guardian review is open for proposal #${proposalId}. openReview must run (and the shareholder vote must have ended) before guardians can vote.`
|
|
6949
|
+
));
|
|
6950
|
+
process.exit(1);
|
|
6951
|
+
}
|
|
6952
|
+
if (resolved) {
|
|
6953
|
+
console.error(chalk9.red(`Guardian review for proposal #${proposalId} is already resolved.`));
|
|
6954
|
+
process.exit(1);
|
|
6955
|
+
}
|
|
6956
|
+
if (now < p.voteEnd) {
|
|
6957
|
+
console.error(chalk9.red(
|
|
6958
|
+
`Shareholder vote is still open until ${formatTimestamp(p.voteEnd)}. Guardian review voting starts after voteEnd.`
|
|
6959
|
+
));
|
|
6960
|
+
process.exit(1);
|
|
6961
|
+
}
|
|
6962
|
+
if (now >= p.reviewEnd) {
|
|
6963
|
+
console.error(chalk9.red(
|
|
6964
|
+
`Review window elapsed at ${formatTimestamp(p.reviewEnd)}. Use \`sherwood proposal resolve-reviews\`.`
|
|
6965
|
+
));
|
|
6966
|
+
process.exit(1);
|
|
6967
|
+
}
|
|
6968
|
+
console.log();
|
|
6969
|
+
console.log(LABEL3(" \u25C6 Guardian Review Vote"));
|
|
6970
|
+
SEP3();
|
|
6971
|
+
console.log(W3(` Proposal: #${proposalId}`));
|
|
6972
|
+
console.log(W3(` Vault: ${G3(p.vault)}`));
|
|
6973
|
+
console.log(W3(` Governor: ${governor}`));
|
|
6974
|
+
console.log(W3(` Strategy: ${p.strategy}`));
|
|
6975
|
+
console.log(W3(` State: ${PROPOSAL_STATES[state] || "Unknown"}`));
|
|
6976
|
+
console.log(W3(` Review ends: ${formatTimestamp(p.reviewEnd)}`));
|
|
6977
|
+
console.log(W3(
|
|
6978
|
+
` Support: ${vote2 === "Approve" ? G3("APPROVE") : chalk9.red("BLOCK")}`
|
|
6979
|
+
));
|
|
6980
|
+
console.log(W3(` Max capital: ${p.maxCapital.toString()} (asset base units)`));
|
|
6981
|
+
console.log(W3(` Required coverage: ${formatUsd18(p.requiredCoverage)} (USD)`));
|
|
6982
|
+
console.log(W3(` Envelope tier: ${p.envelopeTier}`));
|
|
6983
|
+
console.log(W3(` Caller: ${account.address}`));
|
|
6984
|
+
SEP3();
|
|
6985
|
+
if (vote2 === "Approve") {
|
|
6986
|
+
console.log(chalk9.yellow.bold(" \u26A0 UNDERWRITING"));
|
|
6987
|
+
console.log(chalk9.yellow(
|
|
6988
|
+
" Approve books this proposal's coverage against YOUR own slashable"
|
|
6989
|
+
));
|
|
6990
|
+
console.log(chalk9.yellow(
|
|
6991
|
+
" guardian bond (ExposureLedger.recordApproval). If the proposal is"
|
|
6992
|
+
));
|
|
6993
|
+
console.log(chalk9.yellow(
|
|
6994
|
+
" later challenged or slashed, your WOOD stake is at risk \u2014 not"
|
|
6995
|
+
));
|
|
6996
|
+
console.log(chalk9.yellow(
|
|
6997
|
+
" another guardian's. An over-exposed bond books nothing rather than"
|
|
6998
|
+
));
|
|
6999
|
+
console.log(chalk9.yellow(
|
|
7000
|
+
" reverting; the vote still lands and the shortfall shows at execute."
|
|
7001
|
+
));
|
|
7002
|
+
SEP3();
|
|
7003
|
+
}
|
|
7004
|
+
const action = encodeVoteOnProposal({ governor, proposalId, vote: vote2 }, chainId);
|
|
7005
|
+
const tx = action.txs[0];
|
|
7006
|
+
const voteSpinner = ora7({ text: W3("Submitting review vote..."), color: "green" }).start();
|
|
7007
|
+
const hash = await sendTxWithRetry({
|
|
7008
|
+
account,
|
|
7009
|
+
chain: getChain(),
|
|
7010
|
+
to: tx.to,
|
|
7011
|
+
data: tx.data,
|
|
7012
|
+
value: BigInt(tx.value)
|
|
7013
|
+
});
|
|
7014
|
+
await waitForReceipt(hash);
|
|
7015
|
+
voteSpinner.succeed(G3(`Review vote cast (${vote2})`));
|
|
7016
|
+
console.log(DIM3(` ${getExplorerUrl(hash)}`));
|
|
7017
|
+
console.log();
|
|
7018
|
+
} catch (err) {
|
|
7019
|
+
console.error(chalk9.red(`
|
|
7020
|
+
\u2716 ${formatContractError(err)}`));
|
|
7021
|
+
process.exit(1);
|
|
7022
|
+
}
|
|
7023
|
+
});
|
|
6368
7024
|
proposal.command("execute").description("Execute an approved proposal").requiredOption("--id <proposalId>", "Proposal ID").requiredOption("--vault <address>", "Vault the proposal belongs to (per-vault governor)").option("--dry-run", "Simulate execution without sending a transaction").action(async (opts) => {
|
|
6369
7025
|
try {
|
|
6370
7026
|
const proposalId = parseBigIntArg(opts.id, "proposal ID");
|
|
@@ -6635,6 +7291,113 @@ function registerProposalCommands(program2) {
|
|
|
6635
7291
|
process.exit(1);
|
|
6636
7292
|
}
|
|
6637
7293
|
});
|
|
7294
|
+
proposal.command("open-reviews").description("Keeper: open guardian reviews whose vote has ended (window [voteEnd, reviewEnd))").requiredOption("--vault <address>", "Vault whose governor's reviews to scan (per-vault governor)").option("--dry-run", "List openable reviews without sending transactions").action(async (opts) => {
|
|
7295
|
+
const spinner = ora7("Scanning proposals for openable reviews...").start();
|
|
7296
|
+
try {
|
|
7297
|
+
const vault = parseVaultOption(opts.vault, spinner);
|
|
7298
|
+
const registryAddr = getRegistryAddress();
|
|
7299
|
+
const pc = getPublicClient();
|
|
7300
|
+
const governorAddr = await getGovernorOf(vault);
|
|
7301
|
+
const count = await proposalCount(vault);
|
|
7302
|
+
if (count === 0n) {
|
|
7303
|
+
spinner.stop();
|
|
7304
|
+
console.log(DIM3("\n No proposals \u2014 nothing to open.\n"));
|
|
7305
|
+
return;
|
|
7306
|
+
}
|
|
7307
|
+
const now = (await pc.getBlock()).timestamp;
|
|
7308
|
+
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
7309
|
+
const { candidates, failures: scanFailures } = await scanReviewCandidates(
|
|
7310
|
+
ids,
|
|
7311
|
+
async (id) => {
|
|
7312
|
+
const [p, reviewState] = await Promise.all([
|
|
7313
|
+
getProposal(vault, id),
|
|
7314
|
+
pc.readContract({
|
|
7315
|
+
address: registryAddr,
|
|
7316
|
+
abi: GUARDIAN_REGISTRY_ABI2,
|
|
7317
|
+
functionName: "getReviewState",
|
|
7318
|
+
args: [governorAddr, id]
|
|
7319
|
+
})
|
|
7320
|
+
]);
|
|
7321
|
+
const [opened, resolved] = reviewState;
|
|
7322
|
+
const cls = classifyReviewOpen({
|
|
7323
|
+
opened,
|
|
7324
|
+
resolved,
|
|
7325
|
+
voteEnd: p.voteEnd,
|
|
7326
|
+
reviewEnd: p.reviewEnd,
|
|
7327
|
+
now
|
|
7328
|
+
});
|
|
7329
|
+
return { id, cls, reviewEnd: p.reviewEnd, vault: p.vault };
|
|
7330
|
+
}
|
|
7331
|
+
);
|
|
7332
|
+
const openable = candidates.filter((c) => c.cls === "openable");
|
|
7333
|
+
spinner.stop();
|
|
7334
|
+
const scanIncomplete = scanFailures.length > 0;
|
|
7335
|
+
if (scanIncomplete) {
|
|
7336
|
+
console.log();
|
|
7337
|
+
for (const f of scanFailures) {
|
|
7338
|
+
console.log(
|
|
7339
|
+
chalk9.yellow(` \u26A0 Proposal #${f.id} failed to load: ${formatContractError(f.error)}`)
|
|
7340
|
+
);
|
|
7341
|
+
}
|
|
7342
|
+
console.log(
|
|
7343
|
+
chalk9.yellow(
|
|
7344
|
+
` \u26A0 ${scanFailures.length} of ${ids.length} proposals failed to load \u2014 treat this run as incomplete.`
|
|
7345
|
+
)
|
|
7346
|
+
);
|
|
7347
|
+
}
|
|
7348
|
+
if (openable.length === 0) {
|
|
7349
|
+
console.log(DIM3("\n No reviews ready to open.\n"));
|
|
7350
|
+
if (scanIncomplete) process.exit(1);
|
|
7351
|
+
return;
|
|
7352
|
+
}
|
|
7353
|
+
console.log();
|
|
7354
|
+
console.log(LABEL3(` \u25C6 Openable Guardian Reviews (${openable.length})`));
|
|
7355
|
+
SEP3();
|
|
7356
|
+
for (const c of openable) {
|
|
7357
|
+
console.log(
|
|
7358
|
+
W3(` Proposal #${c.id} vault=${c.vault} reviewEnd=${formatTimestamp(c.reviewEnd)}`)
|
|
7359
|
+
);
|
|
7360
|
+
}
|
|
7361
|
+
SEP3();
|
|
7362
|
+
if (opts.dryRun) {
|
|
7363
|
+
console.log(G3("\n (dry-run) Not broadcasting. Re-run without --dry-run to open.\n"));
|
|
7364
|
+
if (scanIncomplete) process.exit(1);
|
|
7365
|
+
return;
|
|
7366
|
+
}
|
|
7367
|
+
const openedOk = [];
|
|
7368
|
+
for (const c of openable) {
|
|
7369
|
+
const txSpinner = ora7(`Opening review for proposal #${c.id}...`).start();
|
|
7370
|
+
try {
|
|
7371
|
+
const hash = await writeContractWithRetry({
|
|
7372
|
+
account: getAccount(),
|
|
7373
|
+
chain: getChain(),
|
|
7374
|
+
address: registryAddr,
|
|
7375
|
+
abi: GUARDIAN_REGISTRY_ABI2,
|
|
7376
|
+
functionName: "openReview",
|
|
7377
|
+
args: [governorAddr, c.id]
|
|
7378
|
+
});
|
|
7379
|
+
assertReceiptSuccess(await waitForReceipt(hash));
|
|
7380
|
+
openedOk.push({ id: c.id, hash });
|
|
7381
|
+
txSpinner.succeed(G3(`Proposal #${c.id} review opened`));
|
|
7382
|
+
} catch (err) {
|
|
7383
|
+
txSpinner.fail(`Proposal #${c.id} open failed: ${formatContractError(err)}`);
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
console.log();
|
|
7387
|
+
console.log(LABEL3(` \u25C6 Opened ${openedOk.length}/${openable.length}`));
|
|
7388
|
+
SEP3();
|
|
7389
|
+
for (const r of openedOk) {
|
|
7390
|
+
console.log(W3(` Proposal #${r.id} `) + DIM3(getExplorerUrl(r.hash)));
|
|
7391
|
+
}
|
|
7392
|
+
SEP3();
|
|
7393
|
+
console.log();
|
|
7394
|
+
if (openedOk.length < openable.length || scanIncomplete) process.exit(1);
|
|
7395
|
+
} catch (err) {
|
|
7396
|
+
spinner.fail("Failed to scan reviews");
|
|
7397
|
+
console.error(chalk9.red(formatContractError(err)));
|
|
7398
|
+
process.exit(1);
|
|
7399
|
+
}
|
|
7400
|
+
});
|
|
6638
7401
|
proposal.command("resolve-reviews").description("Keeper: resolve guardian reviews whose review window has elapsed").requiredOption("--vault <address>", "Vault whose governor's reviews to scan (per-vault governor)").option("--dry-run", "List resolvable reviews without sending transactions").action(async (opts) => {
|
|
6639
7402
|
const spinner = ora7("Scanning proposals for resolvable reviews...").start();
|
|
6640
7403
|
try {
|
|
@@ -6650,29 +7413,40 @@ function registerProposalCommands(program2) {
|
|
|
6650
7413
|
}
|
|
6651
7414
|
const now = (await pc.getBlock()).timestamp;
|
|
6652
7415
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
6653
|
-
const candidates = await
|
|
6654
|
-
ids
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
return { id, cls: "none", reviewEnd: 0n, vault: "0x" };
|
|
6670
|
-
}
|
|
6671
|
-
})
|
|
7416
|
+
const { candidates, failures: scanFailures } = await scanReviewCandidates(
|
|
7417
|
+
ids,
|
|
7418
|
+
async (id) => {
|
|
7419
|
+
const [p, reviewState] = await Promise.all([
|
|
7420
|
+
getProposal(vault, id),
|
|
7421
|
+
pc.readContract({
|
|
7422
|
+
address: registryAddr,
|
|
7423
|
+
abi: GUARDIAN_REGISTRY_ABI2,
|
|
7424
|
+
functionName: "getReviewState",
|
|
7425
|
+
args: [governorAddr, id]
|
|
7426
|
+
})
|
|
7427
|
+
]);
|
|
7428
|
+
const [opened, resolved2] = reviewState;
|
|
7429
|
+
const cls = classifyReview({ opened, resolved: resolved2, reviewEnd: p.reviewEnd, now });
|
|
7430
|
+
return { id, cls, reviewEnd: p.reviewEnd, vault: p.vault };
|
|
7431
|
+
}
|
|
6672
7432
|
);
|
|
6673
7433
|
const resolvable = candidates.filter((c) => c.cls === "resolvable");
|
|
6674
7434
|
const coldStart = candidates.filter((c) => c.cls === "cold-start");
|
|
6675
7435
|
spinner.stop();
|
|
7436
|
+
const scanIncomplete = scanFailures.length > 0;
|
|
7437
|
+
if (scanIncomplete) {
|
|
7438
|
+
console.log();
|
|
7439
|
+
for (const f of scanFailures) {
|
|
7440
|
+
console.log(
|
|
7441
|
+
chalk9.yellow(` \u26A0 Proposal #${f.id} failed to load: ${formatContractError(f.error)}`)
|
|
7442
|
+
);
|
|
7443
|
+
}
|
|
7444
|
+
console.log(
|
|
7445
|
+
chalk9.yellow(
|
|
7446
|
+
` \u26A0 ${scanFailures.length} of ${ids.length} proposals failed to load \u2014 treat this run as incomplete.`
|
|
7447
|
+
)
|
|
7448
|
+
);
|
|
7449
|
+
}
|
|
6676
7450
|
if (coldStart.length > 0) {
|
|
6677
7451
|
console.log();
|
|
6678
7452
|
console.log(LABEL3(` \u25C6 Unopened Cold-Start Reviews (${coldStart.length})`));
|
|
@@ -6697,6 +7471,7 @@ function registerProposalCommands(program2) {
|
|
|
6697
7471
|
} else {
|
|
6698
7472
|
console.log(DIM3("\n No opened reviews need an on-chain resolve.\n"));
|
|
6699
7473
|
}
|
|
7474
|
+
if (scanIncomplete) process.exit(1);
|
|
6700
7475
|
return;
|
|
6701
7476
|
}
|
|
6702
7477
|
console.log();
|
|
@@ -6710,6 +7485,7 @@ function registerProposalCommands(program2) {
|
|
|
6710
7485
|
SEP3();
|
|
6711
7486
|
if (opts.dryRun) {
|
|
6712
7487
|
console.log(G3("\n (dry-run) Not broadcasting. Re-run without --dry-run to resolve.\n"));
|
|
7488
|
+
if (scanIncomplete) process.exit(1);
|
|
6713
7489
|
return;
|
|
6714
7490
|
}
|
|
6715
7491
|
const resolved = [];
|
|
@@ -6731,7 +7507,7 @@ function registerProposalCommands(program2) {
|
|
|
6731
7507
|
functionName: "resolveReview",
|
|
6732
7508
|
args: [governorAddr, c.id]
|
|
6733
7509
|
});
|
|
6734
|
-
await waitForReceipt(hash);
|
|
7510
|
+
assertReceiptSuccess(await waitForReceipt(hash));
|
|
6735
7511
|
resolved.push({ id: c.id, blocked, hash });
|
|
6736
7512
|
txSpinner.succeed(
|
|
6737
7513
|
G3(`Proposal #${c.id} resolved \u2014 blocked=${blocked ? chalk9.red("true") : "false"}`)
|
|
@@ -6750,7 +7526,7 @@ function registerProposalCommands(program2) {
|
|
|
6750
7526
|
}
|
|
6751
7527
|
SEP3();
|
|
6752
7528
|
console.log();
|
|
6753
|
-
if (resolved.length < resolvable.length) process.exit(1);
|
|
7529
|
+
if (resolved.length < resolvable.length || scanIncomplete) process.exit(1);
|
|
6754
7530
|
} catch (err) {
|
|
6755
7531
|
spinner.fail("Failed to scan reviews");
|
|
6756
7532
|
console.error(chalk9.red(formatContractError(err)));
|
|
@@ -10027,9 +10803,9 @@ try {
|
|
|
10027
10803
|
} catch {
|
|
10028
10804
|
}
|
|
10029
10805
|
var require2 = createRequire(import.meta.url);
|
|
10030
|
-
var CLI_VERSION = "0.
|
|
10806
|
+
var CLI_VERSION = "0.84.0";
|
|
10031
10807
|
async function loadXmtp() {
|
|
10032
|
-
return import("./xmtp-
|
|
10808
|
+
return import("./xmtp-S7IGTIMZ.js");
|
|
10033
10809
|
}
|
|
10034
10810
|
async function loadCron() {
|
|
10035
10811
|
return import("./cron-E3UAZF5B.js");
|
|
@@ -10652,7 +11428,7 @@ fund.command("add").description("Register an agent on a fund vault (creator only
|
|
|
10652
11428
|
if (opts.agentId) {
|
|
10653
11429
|
agentId = BigInt(opts.agentId);
|
|
10654
11430
|
} else {
|
|
10655
|
-
const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-
|
|
11431
|
+
const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-LFYVOPOH.js");
|
|
10656
11432
|
const registry = AGENT_REGISTRY2().IDENTITY_REGISTRY;
|
|
10657
11433
|
if (registry === "0x0000000000000000000000000000000000000000") {
|
|
10658
11434
|
agentId = 0n;
|
|
@@ -10858,7 +11634,7 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
|
|
|
10858
11634
|
}
|
|
10859
11635
|
spinner.text = "Creating join request attestation...";
|
|
10860
11636
|
const referrerAgentId = opts.ref ? parseInt(opts.ref, 10) : void 0;
|
|
10861
|
-
const
|
|
11637
|
+
const joinAttestation = await createJoinRequest(
|
|
10862
11638
|
fund2.id,
|
|
10863
11639
|
BigInt(agentId),
|
|
10864
11640
|
fund2.vault,
|
|
@@ -10893,9 +11669,12 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
|
|
|
10893
11669
|
console.log(W6(` Fund: ${G6(`${subdomain}.sherwoodagent.eth`)}`));
|
|
10894
11670
|
console.log(W6(` Agent ID: #${agentId}`));
|
|
10895
11671
|
console.log(W6(` Creator: ${DIM6(fund2.creator)}`));
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
11672
|
+
if (joinAttestation) {
|
|
11673
|
+
console.log(W6(` Attestation: ${DIM6(joinAttestation.uid)}`));
|
|
11674
|
+
console.log(W6(` Explorer: ${DIM6(getEasExplorerUrl(joinAttestation.hash))}`));
|
|
11675
|
+
} else {
|
|
11676
|
+
console.log(W6(` Attestation: ${DIM6("skipped on this chain")}`));
|
|
11677
|
+
}
|
|
10899
11678
|
SEP6();
|
|
10900
11679
|
console.log(G6(" \u2713 Fund saved to ~/.sherwood/config.json (set as primary)"));
|
|
10901
11680
|
console.log(G6(" \u2713 The creator can review with:"));
|
|
@@ -11056,7 +11835,7 @@ fund.command("approve").description("Approve an agent join request (registers ag
|
|
|
11056
11835
|
vaultAddress,
|
|
11057
11836
|
agentWallet
|
|
11058
11837
|
);
|
|
11059
|
-
approvalUid = result
|
|
11838
|
+
approvalUid = result?.uid ?? null;
|
|
11060
11839
|
}
|
|
11061
11840
|
try {
|
|
11062
11841
|
spinner.text = "Adding to chat...";
|
|
@@ -11081,8 +11860,9 @@ fund.command("approve").description("Approve an agent join request (registers ag
|
|
|
11081
11860
|
SEP6();
|
|
11082
11861
|
console.log(W6(` Agent ID: #${opts.agentId}`));
|
|
11083
11862
|
console.log(W6(` Wallet: ${G6(opts.wallet)}`));
|
|
11084
|
-
console.log(
|
|
11085
|
-
|
|
11863
|
+
console.log(
|
|
11864
|
+
W6(` Approval: ${DIM6(approvalUid ?? "skipped on this chain")}`)
|
|
11865
|
+
);
|
|
11086
11866
|
SEP6();
|
|
11087
11867
|
} catch (err) {
|
|
11088
11868
|
spinner.fail("Approval failed");
|
|
@@ -11094,8 +11874,12 @@ fund.command("reject").description("Reject a join request by revoking its attest
|
|
|
11094
11874
|
const spinner = ora10("Revoking attestation...").start();
|
|
11095
11875
|
try {
|
|
11096
11876
|
const hash = await revokeJoinRequest(opts.attestation);
|
|
11097
|
-
|
|
11098
|
-
|
|
11877
|
+
if (!hash) {
|
|
11878
|
+
spinner.info("Revocation skipped: attestation writes are disabled on this chain");
|
|
11879
|
+
} else {
|
|
11880
|
+
spinner.succeed("Join request rejected");
|
|
11881
|
+
console.log(DIM6(` ${getEasExplorerUrl(hash)}`));
|
|
11882
|
+
}
|
|
11099
11883
|
} catch (err) {
|
|
11100
11884
|
spinner.fail("Rejection failed");
|
|
11101
11885
|
console.error(chalk18.red(formatContractError(err)));
|
|
@@ -11399,7 +12183,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
|
|
|
11399
12183
|
var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
|
|
11400
12184
|
registerStrategyTemplateCommands(strategy);
|
|
11401
12185
|
program.command("providers").description("List available providers (research + swap routing)").action(async () => {
|
|
11402
|
-
const { listProviders } = await import("./providers-
|
|
12186
|
+
const { listProviders } = await import("./providers-BMOHHVUN.js");
|
|
11403
12187
|
for (const info of listProviders()) {
|
|
11404
12188
|
console.log(`
|
|
11405
12189
|
${info.name} (${info.type})`);
|
|
@@ -11409,7 +12193,7 @@ ${info.name} (${info.type})`);
|
|
|
11409
12193
|
}
|
|
11410
12194
|
});
|
|
11411
12195
|
try {
|
|
11412
|
-
const { registerChatCommands } = await import("./chat-
|
|
12196
|
+
const { registerChatCommands } = await import("./chat-UZ3BBEXV.js");
|
|
11413
12197
|
registerChatCommands(program);
|
|
11414
12198
|
} catch {
|
|
11415
12199
|
program.command("chat <name> [action] [actionArgs...]").description("Fund chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
|
|
@@ -11419,7 +12203,7 @@ try {
|
|
|
11419
12203
|
process.exit(1);
|
|
11420
12204
|
});
|
|
11421
12205
|
}
|
|
11422
|
-
var { registerSessionCommands } = await import("./session-
|
|
12206
|
+
var { registerSessionCommands } = await import("./session-RMAIFRS6.js");
|
|
11423
12207
|
registerSessionCommands(program);
|
|
11424
12208
|
registerVeniceCommands(program);
|
|
11425
12209
|
registerAllowanceCommands(program);
|
|
@@ -11428,11 +12212,11 @@ registerProposalCommands(program);
|
|
|
11428
12212
|
registerQueueCommands(program);
|
|
11429
12213
|
registerGovernorCommands(program);
|
|
11430
12214
|
registerGuardianCommands(program);
|
|
11431
|
-
var { registerResearchCommands } = await import("./research-
|
|
12215
|
+
var { registerResearchCommands } = await import("./research-YSNJ5HTM.js");
|
|
11432
12216
|
registerResearchCommands(program);
|
|
11433
|
-
var { registerAgentCommands } = await import("./agent-
|
|
12217
|
+
var { registerAgentCommands } = await import("./agent-TBLC3WNJ.js");
|
|
11434
12218
|
registerAgentCommands(program);
|
|
11435
|
-
var { registerTradeCommands } = await import("./trade-
|
|
12219
|
+
var { registerTradeCommands } = await import("./trade-YPLTIS56.js");
|
|
11436
12220
|
registerTradeCommands(program);
|
|
11437
12221
|
registerGridCommand(program);
|
|
11438
12222
|
var configCmd = program.command("config");
|