@sage-protocol/cli 0.3.7 → 0.3.10
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/cli/claude-desktop-config.json +1 -1
- package/dist/cli/commands/bounty.js +123 -85
- package/dist/cli/commands/doctor.js +18 -7
- package/dist/cli/commands/personal.js +154 -103
- package/dist/cli/commands/premium-pre.js +23 -875
- package/dist/cli/commands/premium.js +237 -667
- package/dist/cli/commands/sxxx.js +103 -0
- package/dist/cli/commands/timelock.js +17 -186
- package/dist/cli/index.js +1 -5
- package/dist/cli/mcp-setup.md +2 -2
- package/dist/cli/utils/aliases.js +3 -1
- package/dist/cli/utils/error-handler.js +9 -9
- package/dist/cli/utils/lit.js +103 -0
- package/dist/cli/utils/personal-helpers.js +1 -1
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"RPC_URL": "https://sepolia.base.org",
|
|
8
8
|
"LIBRARY_REGISTRY_ADDRESS": "0x032F2E93549640a319163Ba600fc50bA1AFBE50F",
|
|
9
9
|
"SUBDAO_FACTORY_ADDRESS": "0x6bb6A83149F84Df0584aC863e5fE3416AFb214aC",
|
|
10
|
-
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
10
|
+
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.1/gn",
|
|
11
11
|
"PINATA_JWT": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiI4ODE2MWM1Ni05NTYzLTQyNTUtYTU4Ni0xMzBiMTUyMWIxNmIiLCJlbWFpbCI6InRlcnJlbmV0d2VsbHM0N0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGluX3BvbGljeSI6eyJyZWdpb25zIjpbeyJkZXNpcmVkUmVwbGljYXRpb25Db3VudCI6MSwiaWQiOiJGUkExIn0seyJkZXNpcmVkUmVwbGljYXRpb25Db3VudCI6MSwiaWQiOiJOWUMxIn1dLCJ2ZXJzaW9uIjoxfSwibWZhX2VuYWJsZWQiOmZhbHNlLCJzdGF0dXMiOiJBQ1RJVkUifSwiYXV0aGVudGljYXRpb25UeXBlIjoic2NvcGVkS2V5Iiwic2NvcGVkS2V5S2V5IjoiMDRjZWY4NzE5OTg1ODE1M2U5Y2IiLCJzY29wZWRLZXlTZWNyZXQiOiJmNDFjMDVhZTNjN2EzMTliOTAxZjhiNGI3YjMxMDljMThmNjgyZmRkZGY3OGU1ZmZkZjQ4MTM4OTQ0OWUyOGVjIiwiZXhwIjoxNzk1NTMzNTA4fQ.tQKFU7aZ3EKb7RkB99QTaWVduaaKaKjEa1nk43aeSlo"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -6,6 +6,7 @@ const { ethers } = require('ethers');
|
|
|
6
6
|
const { resolveArtifact } = require('../utils/artifacts');
|
|
7
7
|
const { getSignerSession } = require('../utils/cli-session');
|
|
8
8
|
const { handleCLIError } = require('../utils/error-handler');
|
|
9
|
+
const { resolveGovContext } = require('../utils/gov-context');
|
|
9
10
|
|
|
10
11
|
function hex32(id) {
|
|
11
12
|
if (!id) throw new Error('Missing id');
|
|
@@ -43,22 +44,6 @@ function deriveBountyId({ idHex, slug, title }) {
|
|
|
43
44
|
return { idHex: ethers.keccak256(ethers.toUtf8Bytes(auto)), source: 'auto', slug: auto };
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
async function getGovernorAddress(subdao) {
|
|
47
|
-
if (subdao) {
|
|
48
|
-
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
49
|
-
try {
|
|
50
|
-
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
51
|
-
const abi = ['function governor() view returns (address)'];
|
|
52
|
-
const sub = new ethers.Contract(subdao, abi, provider);
|
|
53
|
-
return await sub.governor();
|
|
54
|
-
} catch (e) {
|
|
55
|
-
console.log(`⚠️ Could not get governor from SubDAO: ${e.message}`);
|
|
56
|
-
return process.env.GOV;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return process.env.GOV;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
47
|
async function maybeEnsureSxxxAllowance(governorAddr, defaultAmountEther = '100') {
|
|
63
48
|
try {
|
|
64
49
|
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
@@ -91,40 +76,6 @@ async function maybeEnsureSxxxAllowance(governorAddr, defaultAmountEther = '100'
|
|
|
91
76
|
}
|
|
92
77
|
}
|
|
93
78
|
|
|
94
|
-
async function resolveGovContext(options) {
|
|
95
|
-
let subdao = options.subdao || process.env.WORKING_SUBDAO_ADDRESS || process.env.SUBDAO;
|
|
96
|
-
let governorAddr = process.env.GOV;
|
|
97
|
-
|
|
98
|
-
if (subdao) {
|
|
99
|
-
governorAddr = await getGovernorAddress(subdao);
|
|
100
|
-
} else {
|
|
101
|
-
// Fallback to wizard to select a SubDAO or main gov
|
|
102
|
-
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
103
|
-
const { scope } = await inquirer.prompt([
|
|
104
|
-
{
|
|
105
|
-
type: 'list', name: 'scope', message: 'Select governance context', choices: [
|
|
106
|
-
{ name: 'A SubDAO (recommended)', value: 'subdao' },
|
|
107
|
-
{ name: 'Main protocol (use GOV from env)', value: 'main' }
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
]);
|
|
111
|
-
|
|
112
|
-
if (scope === 'subdao') {
|
|
113
|
-
// For now, use a simple prompt for SubDAO address
|
|
114
|
-
const { subdaoAddr } = await inquirer.prompt([
|
|
115
|
-
{ type: 'input', name: 'subdaoAddr', message: 'Enter SubDAO address:' }
|
|
116
|
-
]);
|
|
117
|
-
subdao = subdaoAddr;
|
|
118
|
-
governorAddr = await getGovernorAddress(subdao);
|
|
119
|
-
process.env.SUBDAO = subdao;
|
|
120
|
-
process.env.WORKING_SUBDAO_ADDRESS = subdao;
|
|
121
|
-
cliConfig.writeAddresses({ SUBDAO: subdao, WORKING_SUBDAO_ADDRESS: subdao, GOV: governorAddr });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return { governorAddr, subdao };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
79
|
function register(program) {
|
|
129
80
|
const bounty = new Command('bounty')
|
|
130
81
|
.description('Enhanced bounty management (create, claim, complete, approve)')
|
|
@@ -142,17 +93,17 @@ function register(program) {
|
|
|
142
93
|
.option('--salt <hex32>', 'Salt (0x... 32 bytes). Default random')
|
|
143
94
|
.option('--delay <sec>', 'Override delay seconds (default Timelock value)')
|
|
144
95
|
.option('--execute', 'Execute immediately if delay=0', false)
|
|
145
|
-
.option('--subdao <address>', 'Resolve Timelock from SubDAO')
|
|
96
|
+
.option('--subdao <address>', 'Resolve Timelock from DAO/SubDAO')
|
|
97
|
+
.option('--dao <address>', 'Alias for --subdao (DAO/SubDAO)')
|
|
146
98
|
.option('--gov <address>', 'Resolve Timelock via Governor')
|
|
147
99
|
.action(async (opts) => {
|
|
148
100
|
try {
|
|
149
101
|
const { ethers } = require('ethers');
|
|
150
|
-
const { resolveGovContext } = require('../utils/gov-context');
|
|
151
102
|
const wm = new (require('@sage-protocol/wallet-manager'))();
|
|
152
103
|
await wm.connect();
|
|
153
104
|
const signer = wm.getSigner();
|
|
154
105
|
const provider = wm.getProvider();
|
|
155
|
-
const ctx = await resolveGovContext({ govOpt: opts.gov, subdaoOpt: opts.subdao, provider });
|
|
106
|
+
const ctx = await resolveGovContext({ govOpt: opts.gov, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
156
107
|
const tlAddr = ctx.timelock || process.env.TIMELOCK || process.env.TIMELOCK_ADDRESS;
|
|
157
108
|
if (!tlAddr) throw new Error('Timelock not resolved. Pass --subdao or set TIMELOCK');
|
|
158
109
|
const tlAbi = resolveArtifact('contracts/cloneable/TimelockControllerCloneable.sol/TimelockControllerCloneable.json').abi;
|
|
@@ -193,7 +144,8 @@ function register(program) {
|
|
|
193
144
|
bounty
|
|
194
145
|
.command('set-mode')
|
|
195
146
|
.description('Set bounty winner mode: auto | board | token')
|
|
196
|
-
.requiredOption('--subdao <address>', 'SubDAO to derive timelock/governor')
|
|
147
|
+
.requiredOption('--subdao <address>', 'DAO/SubDAO to derive timelock/governor')
|
|
148
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
197
149
|
.requiredOption('--mode <mode>', 'auto | board | token')
|
|
198
150
|
.option('--fast-track <wei>', 'Auto mode: fast-track limit in wei', (value) => BigInt(value))
|
|
199
151
|
.option('--operator <address>', 'Board mode: operator Safe/EOA address')
|
|
@@ -207,7 +159,7 @@ function register(program) {
|
|
|
207
159
|
await sdk.bounty.configureWinnerMode({
|
|
208
160
|
provider,
|
|
209
161
|
signer,
|
|
210
|
-
subdao: opts.subdao,
|
|
162
|
+
subdao: opts.subdao || opts.dao,
|
|
211
163
|
mode: String(opts.mode || '').toLowerCase(),
|
|
212
164
|
fastTrackLimit: opts.fastTrack ?? defaultFastTrack,
|
|
213
165
|
governanceConfig: opts.governanceConfig,
|
|
@@ -225,7 +177,8 @@ function register(program) {
|
|
|
225
177
|
bounty
|
|
226
178
|
.command('fund')
|
|
227
179
|
.description('Fund a bounty via Governor proposal (approve + increaseReward)')
|
|
228
|
-
.requiredOption('--subdao <address>', 'SubDAO (derives Governor)')
|
|
180
|
+
.requiredOption('--subdao <address>', 'DAO/SubDAO (derives Governor)')
|
|
181
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
229
182
|
.requiredOption('--bounty-system <address>', 'SimpleBountySystem address')
|
|
230
183
|
.requiredOption('--bounty-id <id>', 'Bounty id', (value) => BigInt(value))
|
|
231
184
|
.requiredOption('--token <address>', 'ERC20 token address (e.g. SXXX)')
|
|
@@ -237,7 +190,7 @@ function register(program) {
|
|
|
237
190
|
const { proposalCall } = await sdk.bounty.fundFromTreasury({
|
|
238
191
|
provider,
|
|
239
192
|
signer,
|
|
240
|
-
subdao: opts.subdao,
|
|
193
|
+
subdao: opts.subdao || opts.dao,
|
|
241
194
|
bountySystem: opts.bountySystem,
|
|
242
195
|
bountyId: opts.bountyId,
|
|
243
196
|
token: opts.token,
|
|
@@ -286,7 +239,8 @@ function register(program) {
|
|
|
286
239
|
bounty
|
|
287
240
|
.command('propose-approve')
|
|
288
241
|
.description('Propose approval of bounty completion (token mode)')
|
|
289
|
-
.requiredOption('--subdao <address>', 'SubDAO (derives Governor)')
|
|
242
|
+
.requiredOption('--subdao <address>', 'DAO/SubDAO (derives Governor)')
|
|
243
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
290
244
|
.requiredOption('--bounty-system <address>', 'SimpleBountySystem address')
|
|
291
245
|
.requiredOption('--bounty-id <id>', 'Bounty id', (value) => BigInt(value))
|
|
292
246
|
.requiredOption('--deliverable <cid>', 'Deliverable IPFS CID')
|
|
@@ -297,7 +251,7 @@ function register(program) {
|
|
|
297
251
|
const { proposalCall } = await sdk.bounty.proposeApproveWinner({
|
|
298
252
|
provider,
|
|
299
253
|
signer,
|
|
300
|
-
subdao: opts.subdao,
|
|
254
|
+
subdao: opts.subdao || opts.dao,
|
|
301
255
|
bountySystem: opts.bountySystem,
|
|
302
256
|
bountyId: opts.bountyId,
|
|
303
257
|
deliverable: opts.deliverable,
|
|
@@ -479,15 +433,21 @@ function register(program) {
|
|
|
479
433
|
.option('--ipfs <cid>', 'IPFS CID with detailed specifications')
|
|
480
434
|
.option('--deadline <days>', 'Deadline in days from now', '30')
|
|
481
435
|
.option('--fast-track', 'Enable fast-track approval for small bounties', false)
|
|
482
|
-
.option('--subdao <address>', 'SubDAO context for governance')
|
|
436
|
+
.option('--subdao <address>', 'DAO/SubDAO context for governance')
|
|
437
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
438
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
483
439
|
.action(async (opts) => {
|
|
484
440
|
try {
|
|
485
|
-
const
|
|
441
|
+
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
442
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
443
|
+
const ctx = await resolveGovContext({ govOpt: null, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
444
|
+
const governorAddr = ctx.governor || process.env.GOV;
|
|
445
|
+
const subdao = ctx.subdao || opts.subdao || opts.dao || process.env.WORKING_SUBDAO_ADDRESS || process.env.SUBDAO || null;
|
|
446
|
+
if (!governorAddr) throw new Error('Governor address not resolved. Pass --subdao/--dao or configure GOV/SUBDAO in .sage config.');
|
|
486
447
|
const bountySystem = cliConfig.resolveAddress('SIMPLE_BOUNTY_SYSTEM_ADDRESS');
|
|
487
448
|
if (!bountySystem) throw new Error('SIMPLE_BOUNTY_SYSTEM_ADDRESS not set in environment');
|
|
488
449
|
|
|
489
450
|
// Convert reward to wei
|
|
490
|
-
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
491
451
|
const rewardWei = ethers.parseEther(String(opts.reward)).toString();
|
|
492
452
|
|
|
493
453
|
// Calculate deadline timestamp
|
|
@@ -536,8 +496,17 @@ function register(program) {
|
|
|
536
496
|
console.log('IPFS CID:', ipfsCID);
|
|
537
497
|
console.log('Fast-track eligible:', fastTrackEligible);
|
|
538
498
|
|
|
539
|
-
|
|
540
|
-
const
|
|
499
|
+
let confirm = false;
|
|
500
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
501
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
502
|
+
confirm = true;
|
|
503
|
+
} else {
|
|
504
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
505
|
+
const ans = await inquirer.prompt([
|
|
506
|
+
{ type: 'confirm', name: 'confirm', message: 'Create bounty proposal?', default: true }
|
|
507
|
+
]);
|
|
508
|
+
confirm = !!ans.confirm;
|
|
509
|
+
}
|
|
541
510
|
if (!confirm) return;
|
|
542
511
|
|
|
543
512
|
// Ensure SXXX allowance for bounty system (creator stake)
|
|
@@ -573,7 +542,8 @@ function register(program) {
|
|
|
573
542
|
.command('claim')
|
|
574
543
|
.description('Claim an active bounty')
|
|
575
544
|
.requiredOption('--id <bountyId>', 'Bounty ID to claim')
|
|
576
|
-
.option('--subdao <address>', 'SubDAO context')
|
|
545
|
+
.option('--subdao <address>', 'DAO/SubDAO context')
|
|
546
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
577
547
|
.action(async (opts) => {
|
|
578
548
|
try {
|
|
579
549
|
const bountySystem = cliConfig.resolveAddress('SIMPLE_BOUNTY_SYSTEM_ADDRESS');
|
|
@@ -606,7 +576,8 @@ function register(program) {
|
|
|
606
576
|
.description('Mark bounty as complete with deliverable')
|
|
607
577
|
.requiredOption('--id <bountyId>', 'Bounty ID to complete')
|
|
608
578
|
.requiredOption('--deliverable <ipfs>', 'IPFS CID of deliverable')
|
|
609
|
-
.option('--subdao <address>', 'SubDAO context')
|
|
579
|
+
.option('--subdao <address>', 'DAO/SubDAO context')
|
|
580
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
610
581
|
.action(async (opts) => {
|
|
611
582
|
try {
|
|
612
583
|
const bountySystem = cliConfig.resolveAddress('SIMPLE_BOUNTY_SYSTEM_ADDRESS');
|
|
@@ -636,7 +607,9 @@ function register(program) {
|
|
|
636
607
|
.description('Manually craft a governance proposal to approve bounty completion')
|
|
637
608
|
.requiredOption('--id <bountyId>', 'Bounty ID to approve')
|
|
638
609
|
.option('--proposal <proposalId>', 'Reference proposal ID for context')
|
|
639
|
-
.option('--subdao <address>', 'SubDAO context')
|
|
610
|
+
.option('--subdao <address>', 'DAO/SubDAO context')
|
|
611
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
612
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
640
613
|
.action(async (opts) => {
|
|
641
614
|
try {
|
|
642
615
|
const { governorAddr } = await resolveGovContext(opts);
|
|
@@ -656,8 +629,17 @@ function register(program) {
|
|
|
656
629
|
console.log('Bounty ID:', opts.id);
|
|
657
630
|
console.log('Reference Proposal:', opts.proposal || 'None');
|
|
658
631
|
|
|
659
|
-
|
|
660
|
-
const
|
|
632
|
+
let confirm = false;
|
|
633
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
634
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
635
|
+
confirm = true;
|
|
636
|
+
} else {
|
|
637
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
638
|
+
const ans = await inquirer.prompt([
|
|
639
|
+
{ type: 'confirm', name: 'confirm', message: 'Create approval proposal?', default: true }
|
|
640
|
+
]);
|
|
641
|
+
confirm = !!ans.confirm;
|
|
642
|
+
}
|
|
661
643
|
if (!confirm) return;
|
|
662
644
|
|
|
663
645
|
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
@@ -753,10 +735,15 @@ function register(program) {
|
|
|
753
735
|
.option('--slug <text>', 'Bounty id slug; hashed to bytes32 if provided')
|
|
754
736
|
.option('--id <bytes32>', 'Bounty id bytes32 (takes precedence)')
|
|
755
737
|
.requiredOption('--cid <cid>', 'IPFS CID/URI with bounty details')
|
|
756
|
-
.option('--subdao <address>', 'SubDAO to derive Governor from')
|
|
738
|
+
.option('--subdao <address>', 'DAO/SubDAO to derive Governor from')
|
|
739
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
740
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
757
741
|
.action(async (opts) => {
|
|
758
742
|
try {
|
|
759
|
-
const
|
|
743
|
+
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
744
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
745
|
+
const ctx = await resolveGovContext({ govOpt: null, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
746
|
+
const governorAddr = ctx.governor || process.env.GOV;
|
|
760
747
|
const announcer = opts.announcer || cliConfig.resolveAddress('BOUNTY_ANNOUNCEMENTS_ADDRESS');
|
|
761
748
|
if (!announcer) throw new Error('Missing BountyAnnouncements address. Set BOUNTY_ANNOUNCEMENTS_ADDRESS or pass --announcer');
|
|
762
749
|
|
|
@@ -773,8 +760,17 @@ function register(program) {
|
|
|
773
760
|
console.log('--- Proposal Preview (announce) ---');
|
|
774
761
|
console.log({ targets, values: values.map(v => v.toString()), calldatas, description, derivedId: { idHex, source, slug } });
|
|
775
762
|
|
|
776
|
-
|
|
777
|
-
const
|
|
763
|
+
let confirm = false;
|
|
764
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
765
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
766
|
+
confirm = true;
|
|
767
|
+
} else {
|
|
768
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
769
|
+
const ans = await inquirer.prompt([
|
|
770
|
+
{ type: 'confirm', name: 'confirm', message: 'Submit proposal?', default: true }
|
|
771
|
+
]);
|
|
772
|
+
confirm = !!ans.confirm;
|
|
773
|
+
}
|
|
778
774
|
if (!confirm) return;
|
|
779
775
|
|
|
780
776
|
const WM = require('@sage-protocol/wallet-manager');
|
|
@@ -814,10 +810,15 @@ function register(program) {
|
|
|
814
810
|
.option('--amount <amount>', 'Intended payout amount (units of asset, or wei for ETH)', '0')
|
|
815
811
|
.option('--asset <address>', 'ERC20 token address (omit or 0x0 for ETH)', '0x0000000000000000000000000000000000000000')
|
|
816
812
|
.option('--erc20', 'Treat payout as ERC20 (default ETH if not set)', false)
|
|
817
|
-
.option('--subdao <address>', 'SubDAO to derive Governor from')
|
|
813
|
+
.option('--subdao <address>', 'DAO/SubDAO to derive Governor from')
|
|
814
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
815
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
818
816
|
.action(async (opts) => {
|
|
819
817
|
try {
|
|
820
|
-
const
|
|
818
|
+
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
819
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
820
|
+
const ctx = await resolveGovContext({ govOpt: null, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
821
|
+
const governorAddr = ctx.governor || process.env.GOV;
|
|
821
822
|
const announcer = opts.announcer || process.env.BOUNTY_ANNOUNCEMENTS_ADDRESS;
|
|
822
823
|
if (!announcer) throw new Error('Missing BountyAnnouncements address. Set BOUNTY_ANNOUNCEMENTS_ADDRESS or pass --announcer');
|
|
823
824
|
const winnerAddr = opts.winner || process.env.DEV_WALLET_ADDRESS;
|
|
@@ -839,8 +840,17 @@ function register(program) {
|
|
|
839
840
|
console.log('--- Proposal Preview (winner) ---');
|
|
840
841
|
console.log({ targets, values: values.map(v => v.toString()), calldatas, description, derivedId: { idHex, source, slug } });
|
|
841
842
|
|
|
842
|
-
|
|
843
|
-
const
|
|
843
|
+
let confirm = false;
|
|
844
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
845
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
846
|
+
confirm = true;
|
|
847
|
+
} else {
|
|
848
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
849
|
+
const ans = await inquirer.prompt([
|
|
850
|
+
{ type: 'confirm', name: 'confirm', message: 'Submit proposal?', default: true }
|
|
851
|
+
]);
|
|
852
|
+
confirm = !!ans.confirm;
|
|
853
|
+
}
|
|
844
854
|
if (!confirm) return;
|
|
845
855
|
|
|
846
856
|
const WM = require('@sage-protocol/wallet-manager');
|
|
@@ -866,11 +876,16 @@ function register(program) {
|
|
|
866
876
|
.description('Create a proposal to pay a bounty winner in ETH from Timelock')
|
|
867
877
|
.option('--to <address>', 'Winner address (defaults to DEV_WALLET_ADDRESS)')
|
|
868
878
|
.requiredOption('--amount <eth>', 'Amount in ETH (decimal)')
|
|
869
|
-
.option('--subdao <address>', 'SubDAO to derive Governor from')
|
|
879
|
+
.option('--subdao <address>', 'DAO/SubDAO to derive Governor from')
|
|
880
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
870
881
|
.option('--note <text>', 'Description note')
|
|
882
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
871
883
|
.action(async (opts) => {
|
|
872
884
|
try {
|
|
873
|
-
const
|
|
885
|
+
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
886
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
887
|
+
const ctx = await resolveGovContext({ govOpt: null, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
888
|
+
const governorAddr = ctx.governor || process.env.GOV;
|
|
874
889
|
const to = opts.to || process.env.DEV_WALLET_ADDRESS;
|
|
875
890
|
if (!to) throw new Error('Missing winner address. Set DEV_WALLET_ADDRESS or pass --to');
|
|
876
891
|
|
|
@@ -884,8 +899,17 @@ function register(program) {
|
|
|
884
899
|
console.log('--- Proposal Preview (payout-eth) ---');
|
|
885
900
|
console.log({ targets, values: values.map(v => v.toString()), calldatas, description });
|
|
886
901
|
|
|
887
|
-
|
|
888
|
-
const
|
|
902
|
+
let confirm = false;
|
|
903
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
904
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
905
|
+
confirm = true;
|
|
906
|
+
} else {
|
|
907
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
908
|
+
const ans = await inquirer.prompt([
|
|
909
|
+
{ type: 'confirm', name: 'confirm', message: 'Submit proposal?', default: true }
|
|
910
|
+
]);
|
|
911
|
+
confirm = !!ans.confirm;
|
|
912
|
+
}
|
|
889
913
|
if (!confirm) return;
|
|
890
914
|
|
|
891
915
|
const WM = require('@sage-protocol/wallet-manager');
|
|
@@ -920,11 +944,16 @@ function register(program) {
|
|
|
920
944
|
.option('--token <address>', 'ERC20 token address held by Timelock (defaults to SXXX_TOKEN_ADDRESS)')
|
|
921
945
|
.option('--to <address>', 'Winner address (defaults to DEV_WALLET_ADDRESS)')
|
|
922
946
|
.requiredOption('--amount <units>', 'Token amount in smallest units')
|
|
923
|
-
.option('--subdao <address>', 'SubDAO to derive Governor from')
|
|
947
|
+
.option('--subdao <address>', 'DAO/SubDAO to derive Governor from')
|
|
948
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
924
949
|
.option('--note <text>', 'Description note')
|
|
950
|
+
.option('--yes', 'Skip interactive confirmation prompts', false)
|
|
925
951
|
.action(async (opts) => {
|
|
926
952
|
try {
|
|
927
|
-
const
|
|
953
|
+
const rpcUrl = process.env.RPC_URL || 'https://base-sepolia.publicnode.com';
|
|
954
|
+
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
955
|
+
const ctx = await resolveGovContext({ govOpt: null, subdaoOpt: opts.subdao || opts.dao, provider });
|
|
956
|
+
const governorAddr = ctx.governor || process.env.GOV;
|
|
928
957
|
const token = opts.token || process.env.SXXX_TOKEN_ADDRESS;
|
|
929
958
|
if (!token) throw new Error('Missing token. Set SXXX_TOKEN_ADDRESS or pass --token');
|
|
930
959
|
const to = opts.to || process.env.DEV_WALLET_ADDRESS;
|
|
@@ -941,8 +970,17 @@ function register(program) {
|
|
|
941
970
|
console.log('--- Proposal Preview (payout-erc20) ---');
|
|
942
971
|
console.log({ targets, values: values.map(v => v.toString()), calldatas, description });
|
|
943
972
|
|
|
944
|
-
|
|
945
|
-
const
|
|
973
|
+
let confirm = false;
|
|
974
|
+
const autoYes = String(process.env.SAGE_YES || '').toLowerCase();
|
|
975
|
+
if (opts.yes || autoYes === '1' || autoYes === 'true') {
|
|
976
|
+
confirm = true;
|
|
977
|
+
} else {
|
|
978
|
+
const inquirer = (require('inquirer').default || require('inquirer'));
|
|
979
|
+
const ans = await inquirer.prompt([
|
|
980
|
+
{ type: 'confirm', name: 'confirm', message: 'Submit proposal?', default: true }
|
|
981
|
+
]);
|
|
982
|
+
confirm = !!ans.confirm;
|
|
983
|
+
}
|
|
946
984
|
if (!confirm) return;
|
|
947
985
|
|
|
948
986
|
const WM = require('@sage-protocol/wallet-manager');
|
|
@@ -238,9 +238,14 @@ async function runDoctor(opts = {}) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
// Optional feature addresses (warn-level): Bounty system, etc.
|
|
241
|
+
// Optional feature addresses (warn-level): Bounty system, Boost managers, Premium prompts, etc.
|
|
242
242
|
const featureAddrs = [
|
|
243
|
-
{ key: 'SIMPLE_BOUNTY_SYSTEM_ADDRESS', feature: 'bounty', hint: 'Required for `sage bounty *` commands.' }
|
|
243
|
+
{ key: 'SIMPLE_BOUNTY_SYSTEM_ADDRESS', feature: 'bounty', hint: 'Required for `sage bounty *` commands.' },
|
|
244
|
+
{ key: 'BOOST_MANAGER_ADDRESS', feature: 'boost (merkle)', hint: 'Required for `sage boost fund/status/claim` (Merkle manager).' },
|
|
245
|
+
{ key: 'BOOST_MANAGER_DIRECT_ADDRESS', feature: 'boost (direct)', hint: 'Required for `sage boost create/status/finalize` (direct manager).' },
|
|
246
|
+
{ key: 'PREMIUM_PROMPTS_ADDRESS', feature: 'premium prompts', hint: 'Required for `sage premium *` commands.' },
|
|
247
|
+
{ key: 'PREMIUM_RECEIPT_ADDRESS', feature: 'premium receipts', hint: 'Required for ERC1155 receipt checks (premium.check).' },
|
|
248
|
+
{ key: 'SIMPLE_KEY_STORE_ADDRESS', feature: 'premium keystore', hint: 'Recommended for premium roles wiring and Lit access control.' }
|
|
244
249
|
];
|
|
245
250
|
for (const entry of featureAddrs) {
|
|
246
251
|
const v = process.env[entry.key];
|
|
@@ -319,7 +324,7 @@ async function runDoctor(opts = {}) {
|
|
|
319
324
|
|
|
320
325
|
// 6) Governor diagnostics (mode, roles, quorum, cooldown, stakeRequired)
|
|
321
326
|
try {
|
|
322
|
-
const subdao = opts.subdao || process.env.WORKING_SUBDAO_ADDRESS || process.env.SUBDAO;
|
|
327
|
+
const subdao = opts.subdao || opts.dao || process.env.WORKING_SUBDAO_ADDRESS || process.env.SUBDAO;
|
|
323
328
|
let governorAddr = process.env.GOV;
|
|
324
329
|
if (subdao && provider) {
|
|
325
330
|
const abi = ['function governor() view returns (address)'];
|
|
@@ -764,7 +769,8 @@ function register(program) {
|
|
|
764
769
|
.option('--json', 'Output JSON for CI/scripts', false)
|
|
765
770
|
.option('--registry', 'Also check LibraryRegistry roles (FACTORY_ROLE, LIBRARY_ADMIN_ROLE)', false)
|
|
766
771
|
.option('--cid <cid>', 'Optional CID to warm-test IPFS gateways')
|
|
767
|
-
.option('--subdao <address>', 'Target DAO for mode/roles diagnostics')
|
|
772
|
+
.option('--subdao <address>', 'Target DAO/SubDAO for mode/roles diagnostics')
|
|
773
|
+
.option('--dao <address>', 'Alias for --subdao')
|
|
768
774
|
.option('--fix', 'Attempt to fix detected issues interactively', false)
|
|
769
775
|
.option('--auto-fix', 'Attempt to fix non-interactively with safe defaults', false)
|
|
770
776
|
.action(async (opts) => {
|
|
@@ -823,8 +829,8 @@ function register(program) {
|
|
|
823
829
|
|
|
824
830
|
if (opts.json) {
|
|
825
831
|
// Build JSON object with key facts
|
|
826
|
-
|
|
827
|
-
|
|
832
|
+
const rpcUrl = process.env.RPC_URL || 'https://sepolia.base.org';
|
|
833
|
+
const chainId = Number(process.env.CHAIN_ID || 0);
|
|
828
834
|
const sageHome = _resolveSageHome();
|
|
829
835
|
const out = {
|
|
830
836
|
rpcUrl,
|
|
@@ -834,9 +840,14 @@ function register(program) {
|
|
|
834
840
|
LIBRARY_REGISTRY_ADDRESS: process.env.LIBRARY_REGISTRY_ADDRESS || null,
|
|
835
841
|
SUBDAO_FACTORY_ADDRESS: process.env.SUBDAO_FACTORY_ADDRESS || null,
|
|
836
842
|
SIMPLE_BOUNTY_SYSTEM_ADDRESS: process.env.SIMPLE_BOUNTY_SYSTEM_ADDRESS || null,
|
|
843
|
+
BOOST_MANAGER_ADDRESS: process.env.BOOST_MANAGER_ADDRESS || null,
|
|
844
|
+
BOOST_MANAGER_DIRECT_ADDRESS: process.env.BOOST_MANAGER_DIRECT_ADDRESS || null,
|
|
845
|
+
PREMIUM_PROMPTS_ADDRESS: process.env.PREMIUM_PROMPTS_ADDRESS || null,
|
|
846
|
+
PREMIUM_RECEIPT_ADDRESS: process.env.PREMIUM_RECEIPT_ADDRESS || null,
|
|
847
|
+
SIMPLE_KEY_STORE_ADDRESS: process.env.SIMPLE_KEY_STORE_ADDRESS || null,
|
|
837
848
|
SUBDAO: process.env.WORKING_SUBDAO_ADDRESS || process.env.SUBDAO || null,
|
|
838
849
|
GOV: process.env.GOV || null,
|
|
839
|
-
TIMELOCK: process.env.TIMELOCK || null,
|
|
850
|
+
TIMELOCK: process.env.TIMELOCK || process.env.TIMELOCK_ADDRESS || null,
|
|
840
851
|
SAFE_TX_SERVICE_URL: process.env.SAFE_TX_SERVICE_URL || null,
|
|
841
852
|
SAGE_USE_SAFE_TX_SERVICE: process.env.SAGE_USE_SAFE_TX_SERVICE || null
|
|
842
853
|
},
|