@sage-protocol/cli 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @sage-protocol/cli might be problematic. Click here for more details.
- package/dist/cli/commands/boost.js +339 -62
- package/dist/cli/commands/bounty.js +28 -4
- package/dist/cli/commands/config.js +10 -1
- package/dist/cli/commands/contributor.js +16 -6
- package/dist/cli/commands/discover.js +3 -3
- package/dist/cli/commands/doctor.js +27 -20
- package/dist/cli/commands/governance.js +141 -58
- package/dist/cli/commands/ipfs.js +12 -2
- package/dist/cli/commands/library.js +2 -1
- package/dist/cli/commands/members.js +132 -18
- package/dist/cli/commands/multiplier.js +101 -13
- package/dist/cli/commands/nft.js +16 -3
- package/dist/cli/commands/prompt.js +1 -1
- package/dist/cli/commands/proposals.js +153 -3
- package/dist/cli/commands/stake-status.js +130 -56
- package/dist/cli/commands/sxxx.js +37 -4
- package/dist/cli/contracts/index.js +2 -1
- package/dist/cli/utils/aliases.js +61 -3
- package/package.json +1 -1
|
@@ -11,19 +11,21 @@ function register(program) {
|
|
|
11
11
|
.option('--governor <address>', 'Governor address to check')
|
|
12
12
|
.option('--address <address>', 'Address to check (defaults to connected wallet)')
|
|
13
13
|
.option('-v, --verbose', 'Show detailed output')
|
|
14
|
+
.option('--json', 'Output JSON', false)
|
|
14
15
|
.action(async (opts) => {
|
|
15
16
|
try {
|
|
16
|
-
ui.configure({ verbose: opts.verbose });
|
|
17
|
+
ui.configure({ verbose: opts.verbose, json: opts.json });
|
|
18
|
+
const show = !opts.json;
|
|
17
19
|
|
|
18
20
|
const WalletManager = require('../wallet-manager');
|
|
19
21
|
const { resolveGovContext } = require('../utils/gov-context');
|
|
20
22
|
|
|
21
23
|
const invokedAsStakeStatus = process.argv.includes('stake-status');
|
|
22
|
-
if (invokedAsStakeStatus) {
|
|
24
|
+
if (invokedAsStakeStatus && show) {
|
|
23
25
|
ui.warn('`sage stake-status` is deprecated. Use `sage voting-status` (governance uses delegation, not staking).');
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
const rpcUrl = process.env.RPC_URL || process.env.BASE_SEPOLIA_RPC || 'https://base-sepolia.publicnode.com';
|
|
28
|
+
const rpcUrl = process.env.SAGE_RPC_URL || process.env.RPC_URL || process.env.BASE_SEPOLIA_RPC || 'https://base-sepolia.publicnode.com';
|
|
27
29
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
28
30
|
|
|
29
31
|
// Get wallet manager and connect
|
|
@@ -32,11 +34,13 @@ function register(program) {
|
|
|
32
34
|
const signer = walletManager.getSigner();
|
|
33
35
|
const address = opts.address || await signer.getAddress();
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
[
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (show) {
|
|
38
|
+
ui.header('Voting Power Status');
|
|
39
|
+
ui.keyValue([
|
|
40
|
+
['Address', address],
|
|
41
|
+
['RPC', rpcUrl]
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
40
44
|
|
|
41
45
|
// Resolve governance context
|
|
42
46
|
const ctx = await resolveGovContext({
|
|
@@ -48,14 +52,17 @@ function register(program) {
|
|
|
48
52
|
});
|
|
49
53
|
|
|
50
54
|
if (!ctx.governor) {
|
|
51
|
-
ui.error('No Governor found');
|
|
55
|
+
if (show) ui.error('No Governor found');
|
|
56
|
+
else ui.json({ ok: false, error: 'No Governor found' });
|
|
52
57
|
return;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
[
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
if (show) {
|
|
61
|
+
ui.keyValue([
|
|
62
|
+
['Governor', ctx.governor],
|
|
63
|
+
['SubDAO', ctx.subdao || 'N/A']
|
|
64
|
+
]);
|
|
65
|
+
}
|
|
59
66
|
|
|
60
67
|
// Get Governor's voting token and multiplier status
|
|
61
68
|
const govABI = [
|
|
@@ -78,19 +85,21 @@ function register(program) {
|
|
|
78
85
|
const baseVotesTokenAddr = await governor.baseVotesToken().catch(() => votingToken);
|
|
79
86
|
const isWrapperMode = isMultiplierEnabled || (baseVotesTokenAddr && baseVotesTokenAddr !== votingToken);
|
|
80
87
|
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
[
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
[
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
if (show) {
|
|
89
|
+
if (isWrapperMode) {
|
|
90
|
+
ui.keyValue([
|
|
91
|
+
['Voting Token (wrapper)', votingToken],
|
|
92
|
+
['Base Token (SXXX)', baseVotesTokenAddr],
|
|
93
|
+
['NFT Multipliers', isMultiplierEnabled ? 'Enabled' : 'Unknown']
|
|
94
|
+
]);
|
|
95
|
+
} else {
|
|
96
|
+
ui.keyValue([
|
|
97
|
+
['Voting Token', votingToken],
|
|
98
|
+
['NFT Multipliers', 'Disabled']
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
101
|
+
ui.info(`Proposal Threshold: ${ethers.formatEther(threshold)} tokens`);
|
|
92
102
|
}
|
|
93
|
-
ui.info(`Proposal Threshold: ${ethers.formatEther(threshold)} tokens`);
|
|
94
103
|
|
|
95
104
|
// In multiplier mode, governor.token() is an IVotes wrapper (MultipliedVotes) which is NOT an ERC20,
|
|
96
105
|
// so ERC20 calls (name/symbol/decimals/balanceOf) can revert. Always read ERC20 metadata from the base token.
|
|
@@ -117,35 +126,39 @@ function register(program) {
|
|
|
117
126
|
provider.getBlockNumber()
|
|
118
127
|
]);
|
|
119
128
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
[
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
if (show) {
|
|
130
|
+
ui.newline();
|
|
131
|
+
ui.header('Token Details');
|
|
132
|
+
ui.keyValue([
|
|
133
|
+
['Name', name],
|
|
134
|
+
['Symbol', symbol],
|
|
135
|
+
['Decimals', decimals],
|
|
136
|
+
['Balance', `${ethers.formatUnits(balance, decimals)} ${symbol}`],
|
|
137
|
+
['Delegates to', delegates]
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
129
140
|
|
|
130
141
|
// Check voting power at different blocks
|
|
131
142
|
const blocksToCheck = [currentBlock - 1, currentBlock - 2, currentBlock - 5];
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
if (show) {
|
|
144
|
+
ui.newline();
|
|
145
|
+
ui.header('Voting Power History');
|
|
146
|
+
}
|
|
134
147
|
|
|
135
148
|
for (const block of blocksToCheck) {
|
|
136
149
|
try {
|
|
137
150
|
const votes = await votesToken.getPastVotes(address, block);
|
|
138
151
|
const formattedVotes = ethers.formatUnits(votes, decimals);
|
|
139
152
|
const status = votes >= threshold ? ui.symbols.check : ui.symbols.cross;
|
|
140
|
-
ui.output(` Block ${block}: ${formattedVotes} ${symbol} ${status}`);
|
|
153
|
+
if (show) ui.output(` Block ${block}: ${formattedVotes} ${symbol} ${status}`);
|
|
141
154
|
} catch (e) {
|
|
142
|
-
ui.output(` Block ${block}: Error - ${e.message}`);
|
|
155
|
+
if (show) ui.output(` Block ${block}: Error - ${e.message}`);
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
158
|
|
|
146
159
|
// Note: stakeToken() removed from SubDAO contracts (threshold-based governance)
|
|
147
160
|
// Voting power now comes from SXXX token delegation, not staking
|
|
148
|
-
if (ctx.subdao) {
|
|
161
|
+
if (ctx.subdao && show) {
|
|
149
162
|
ui.newline();
|
|
150
163
|
ui.header('Governance Model');
|
|
151
164
|
ui.output(' This SubDAO uses threshold-based governance.');
|
|
@@ -154,8 +167,10 @@ function register(program) {
|
|
|
154
167
|
|
|
155
168
|
// Summary
|
|
156
169
|
const currentVotes = await votesToken.getPastVotes(address, currentBlock - 1).catch(() => 0n);
|
|
157
|
-
|
|
158
|
-
|
|
170
|
+
if (show) {
|
|
171
|
+
ui.newline();
|
|
172
|
+
ui.header('Summary');
|
|
173
|
+
}
|
|
159
174
|
|
|
160
175
|
// If multipliers are enabled, show both base and effective voting power
|
|
161
176
|
if (isWrapperMode) {
|
|
@@ -163,32 +178,91 @@ function register(program) {
|
|
|
163
178
|
const [baseVotes, multiplier, effectiveVotes] = await governor.getVotingBreakdown(address);
|
|
164
179
|
const multiplierDisplay = (Number(multiplier) / 10000).toFixed(2);
|
|
165
180
|
const canPropose = effectiveVotes >= threshold;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
181
|
+
if (show) {
|
|
182
|
+
ui.keyValue([
|
|
183
|
+
['Base Voting Power', `${ethers.formatUnits(baseVotes, decimals)} ${symbol}`],
|
|
184
|
+
['NFT Multiplier', `${multiplierDisplay}x`],
|
|
185
|
+
['Effective Voting Power', `${ethers.formatUnits(effectiveVotes, decimals)} votes`],
|
|
186
|
+
['Proposal Threshold', `${ethers.formatEther(threshold)} tokens`],
|
|
187
|
+
['Can Propose', canPropose ? 'YES' : 'NO']
|
|
188
|
+
]);
|
|
189
|
+
} else {
|
|
190
|
+
ui.json({
|
|
191
|
+
ok: true,
|
|
192
|
+
address,
|
|
193
|
+
rpcUrl,
|
|
194
|
+
governor: ctx.governor,
|
|
195
|
+
subdao: ctx.subdao || null,
|
|
196
|
+
votingToken,
|
|
197
|
+
baseToken: baseVotesTokenAddr,
|
|
198
|
+
isMultiplierEnabled: !!isMultiplierEnabled,
|
|
199
|
+
threshold: threshold.toString(),
|
|
200
|
+
balance: balance.toString(),
|
|
201
|
+
delegates,
|
|
202
|
+
baseVotes: baseVotes.toString(),
|
|
203
|
+
multiplier: multiplier.toString(),
|
|
204
|
+
effectiveVotes: effectiveVotes.toString(),
|
|
205
|
+
canPropose
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
173
209
|
} catch (e) {
|
|
174
210
|
// Fallback if getVotingBreakdown fails
|
|
175
211
|
const canPropose = currentVotes >= threshold;
|
|
212
|
+
if (show) {
|
|
213
|
+
ui.keyValue([
|
|
214
|
+
['Current Voting Power', `${ethers.formatUnits(currentVotes, decimals)} ${symbol}`],
|
|
215
|
+
['Proposal Threshold', `${ethers.formatEther(threshold)} tokens`],
|
|
216
|
+
['Can Propose', canPropose ? 'YES' : 'NO']
|
|
217
|
+
]);
|
|
218
|
+
} else {
|
|
219
|
+
ui.json({
|
|
220
|
+
ok: true,
|
|
221
|
+
address,
|
|
222
|
+
rpcUrl,
|
|
223
|
+
governor: ctx.governor,
|
|
224
|
+
subdao: ctx.subdao || null,
|
|
225
|
+
votingToken,
|
|
226
|
+
baseToken: baseVotesTokenAddr,
|
|
227
|
+
isMultiplierEnabled: !!isMultiplierEnabled,
|
|
228
|
+
threshold: threshold.toString(),
|
|
229
|
+
balance: balance.toString(),
|
|
230
|
+
delegates,
|
|
231
|
+
currentVotes: currentVotes.toString(),
|
|
232
|
+
canPropose
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
const canPropose = currentVotes >= threshold;
|
|
239
|
+
if (show) {
|
|
176
240
|
ui.keyValue([
|
|
177
241
|
['Current Voting Power', `${ethers.formatUnits(currentVotes, decimals)} ${symbol}`],
|
|
178
242
|
['Proposal Threshold', `${ethers.formatEther(threshold)} tokens`],
|
|
179
243
|
['Can Propose', canPropose ? 'YES' : 'NO']
|
|
180
244
|
]);
|
|
245
|
+
} else {
|
|
246
|
+
ui.json({
|
|
247
|
+
ok: true,
|
|
248
|
+
address,
|
|
249
|
+
rpcUrl,
|
|
250
|
+
governor: ctx.governor,
|
|
251
|
+
subdao: ctx.subdao || null,
|
|
252
|
+
votingToken,
|
|
253
|
+
baseToken: baseVotesTokenAddr,
|
|
254
|
+
isMultiplierEnabled: !!isMultiplierEnabled,
|
|
255
|
+
threshold: threshold.toString(),
|
|
256
|
+
balance: balance.toString(),
|
|
257
|
+
delegates,
|
|
258
|
+
currentVotes: currentVotes.toString(),
|
|
259
|
+
canPropose
|
|
260
|
+
});
|
|
261
|
+
return;
|
|
181
262
|
}
|
|
182
|
-
} else {
|
|
183
|
-
const canPropose = currentVotes >= threshold;
|
|
184
|
-
ui.keyValue([
|
|
185
|
-
['Current Voting Power', `${ethers.formatUnits(currentVotes, decimals)} ${symbol}`],
|
|
186
|
-
['Proposal Threshold', `${ethers.formatEther(threshold)} tokens`],
|
|
187
|
-
['Can Propose', canPropose ? 'YES' : 'NO']
|
|
188
|
-
]);
|
|
189
263
|
}
|
|
190
264
|
|
|
191
|
-
if (currentVotes < threshold) {
|
|
265
|
+
if (show && currentVotes < threshold) {
|
|
192
266
|
ui.newline();
|
|
193
267
|
ui.info('To gain voting power:');
|
|
194
268
|
if (balance === 0n) {
|
|
@@ -22,10 +22,14 @@ function register(program) {
|
|
|
22
22
|
try {
|
|
23
23
|
ui.configure({ verbose: opts.verbose });
|
|
24
24
|
const { ethers } = require('ethers');
|
|
25
|
-
const rpcUrl = cliConfig.resolveRpcUrl();
|
|
25
|
+
const rpcUrl = cliConfig.resolveRpcUrl({ allowEnv: true });
|
|
26
26
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
27
27
|
const tokenAddress = cliConfig.resolveAddress('SXXX_TOKEN_ADDRESS');
|
|
28
28
|
if (!tokenAddress) throw new Error('SXXX_TOKEN_ADDRESS not set');
|
|
29
|
+
const code = await provider.getCode(tokenAddress);
|
|
30
|
+
if (!code || code === '0x' || code === '0x0') {
|
|
31
|
+
throw new Error(`SXXX contract not found at ${tokenAddress}. Check SAGE_RPC_URL/CHAIN_ID or import addresses.`);
|
|
32
|
+
}
|
|
29
33
|
let targetAddress = address;
|
|
30
34
|
// 1) Prefer configured default account from profile
|
|
31
35
|
if (!targetAddress) {
|
|
@@ -46,9 +50,38 @@ function register(program) {
|
|
|
46
50
|
} catch (_) {}
|
|
47
51
|
}
|
|
48
52
|
if (!targetAddress) throw new Error('No address provided and could not resolve wallet account');
|
|
49
|
-
const abi = ['function balanceOf(address) view returns (uint256)'];
|
|
53
|
+
const abi = ['function balanceOf(address) view returns (uint256)', 'function symbol() view returns (string)'];
|
|
50
54
|
const token = new ethers.Contract(tokenAddress, abi, provider);
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
// Verify contract exists and is an ERC20
|
|
57
|
+
try {
|
|
58
|
+
const code = await provider.getCode(tokenAddress);
|
|
59
|
+
if (code === '0x') {
|
|
60
|
+
ui.error(`SXXX contract not deployed at ${tokenAddress}`);
|
|
61
|
+
ui.info(' This may mean the address is incorrect or the network is wrong.');
|
|
62
|
+
ui.info(' Check: RPC_URL, SXXX_TOKEN_ADDRESS, or run `sage doctor` for diagnostics.');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
} catch (codeErr) {
|
|
66
|
+
// Ignore code check failure, proceed with balance check
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let bal;
|
|
70
|
+
try {
|
|
71
|
+
bal = await token.balanceOf(targetAddress);
|
|
72
|
+
} catch (balErr) {
|
|
73
|
+
const errMsg = balErr.message || String(balErr);
|
|
74
|
+
if (errMsg.includes('BAD_DATA') || errMsg.includes('could not decode result')) {
|
|
75
|
+
ui.error(`Contract at ${tokenAddress} returned invalid data for balanceOf()`);
|
|
76
|
+
ui.info(' This usually means the address is not an ERC20 token contract.');
|
|
77
|
+
ui.info(' Possible fixes:');
|
|
78
|
+
ui.info(' - Check SXXX_TOKEN_ADDRESS is correct for your network');
|
|
79
|
+
ui.info(' - Verify RPC_URL points to the correct chain (Base Sepolia)');
|
|
80
|
+
ui.info(' - Run `sage doctor` for full diagnostics');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
throw balErr;
|
|
84
|
+
}
|
|
52
85
|
ui.success(`SXXX Balance for ${ui.formatAddress(targetAddress)}: ${ui.formatToken(bal, { symbol: 'SXXX' })}`);
|
|
53
86
|
} catch (error) {
|
|
54
87
|
handleCLIError('sxxx:balance', error, { exit: true });
|
|
@@ -62,7 +95,7 @@ function register(program) {
|
|
|
62
95
|
.action(async (opts) => {
|
|
63
96
|
try {
|
|
64
97
|
ui.configure({ verbose: opts.verbose });
|
|
65
|
-
const rpcUrl = cliConfig.resolveRpcUrl();
|
|
98
|
+
const rpcUrl = cliConfig.resolveRpcUrl({ allowEnv: true });
|
|
66
99
|
const tokenAddress = cliConfig.resolveAddress('SXXX_TOKEN_ADDRESS');
|
|
67
100
|
if (!tokenAddress) throw new Error('SXXX_TOKEN_ADDRESS not set (configure via .env or .sage profile)');
|
|
68
101
|
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
const { ethers } = require('ethers');
|
|
9
9
|
|
|
10
10
|
// Default RPC URL
|
|
11
|
-
const DEFAULT_RPC = process.env.
|
|
11
|
+
const DEFAULT_RPC = process.env.SAGE_RPC_URL
|
|
12
|
+
|| process.env.RPC_URL
|
|
12
13
|
|| process.env.BASE_SEPOLIA_RPC
|
|
13
14
|
|| 'https://base-sepolia.publicnode.com';
|
|
14
15
|
|
|
@@ -56,6 +56,8 @@ const COMMAND_CATALOG = {
|
|
|
56
56
|
'execute',
|
|
57
57
|
'status',
|
|
58
58
|
'inspect',
|
|
59
|
+
'decode',
|
|
60
|
+
'summary',
|
|
59
61
|
'watch',
|
|
60
62
|
'power',
|
|
61
63
|
'preflight',
|
|
@@ -83,14 +85,22 @@ const COMMAND_CATALOG = {
|
|
|
83
85
|
'votes',
|
|
84
86
|
'snapshot-power',
|
|
85
87
|
'config',
|
|
86
|
-
'timelock
|
|
87
|
-
'authority'
|
|
88
|
+
'timelock',
|
|
89
|
+
'authority',
|
|
90
|
+
// Added missing subcommands
|
|
91
|
+
'decode',
|
|
92
|
+
'summary',
|
|
93
|
+
'cache-show',
|
|
94
|
+
'last',
|
|
95
|
+
'cancel',
|
|
96
|
+
'cancelability'
|
|
88
97
|
],
|
|
89
98
|
subcommandAliases: {
|
|
90
99
|
ls: 'list',
|
|
91
100
|
exec: 'execute',
|
|
92
101
|
q: 'queue',
|
|
93
|
-
status: 'status'
|
|
102
|
+
status: 'status',
|
|
103
|
+
'timelock-info': 'timelock'
|
|
94
104
|
}
|
|
95
105
|
},
|
|
96
106
|
library: {
|
|
@@ -225,6 +235,54 @@ const COMMAND_CATALOG = {
|
|
|
225
235
|
needsSubcommand: false,
|
|
226
236
|
subcommands: ['list', 'run'],
|
|
227
237
|
subcommandAliases: { ls: 'list' }
|
|
238
|
+
},
|
|
239
|
+
nft: {
|
|
240
|
+
aliases: [],
|
|
241
|
+
needsSubcommand: true,
|
|
242
|
+
subcommands: ['doctor', 'list-tiers', 'my-multiplier', 'tier', 'mint', 'public-mint', 'auction'],
|
|
243
|
+
subcommandAliases: { list: 'list-tiers', tiers: 'list-tiers' }
|
|
244
|
+
},
|
|
245
|
+
sbt: {
|
|
246
|
+
aliases: [],
|
|
247
|
+
needsSubcommand: true,
|
|
248
|
+
subcommands: ['list-reasons', 'doctor', 'mint', 'revoke', 'propose-mint', 'propose-revoke'],
|
|
249
|
+
subcommandAliases: { list: 'list-reasons' }
|
|
250
|
+
},
|
|
251
|
+
council: {
|
|
252
|
+
aliases: [],
|
|
253
|
+
needsSubcommand: true,
|
|
254
|
+
subcommands: ['doctor', 'set-config', 'allow', 'show', 'suggest-allowlist', 'exec', 'schedule'],
|
|
255
|
+
subcommandAliases: { status: 'doctor' }
|
|
256
|
+
},
|
|
257
|
+
profile: {
|
|
258
|
+
aliases: [],
|
|
259
|
+
needsSubcommand: true,
|
|
260
|
+
subcommands: ['get', 'set', 'upload', 'interactive'],
|
|
261
|
+
subcommandAliases: { show: 'get' }
|
|
262
|
+
},
|
|
263
|
+
members: {
|
|
264
|
+
aliases: [],
|
|
265
|
+
needsSubcommand: true,
|
|
266
|
+
subcommands: ['list', 'current-stake'],
|
|
267
|
+
subcommandAliases: {}
|
|
268
|
+
},
|
|
269
|
+
multiplier: {
|
|
270
|
+
aliases: [],
|
|
271
|
+
needsSubcommand: true,
|
|
272
|
+
subcommands: ['status', 'calculate', 'describe', 'propose-tier', 'auction'],
|
|
273
|
+
subcommandAliases: {}
|
|
274
|
+
},
|
|
275
|
+
boost: {
|
|
276
|
+
aliases: [],
|
|
277
|
+
needsSubcommand: true,
|
|
278
|
+
subcommands: ['list', 'create', 'set-merkle-root', 'status', 'finalize', 'claim', 'fund'],
|
|
279
|
+
subcommandAliases: {}
|
|
280
|
+
},
|
|
281
|
+
'voting-status': {
|
|
282
|
+
aliases: [],
|
|
283
|
+
needsSubcommand: false,
|
|
284
|
+
subcommands: [],
|
|
285
|
+
subcommandAliases: {}
|
|
228
286
|
}
|
|
229
287
|
};
|
|
230
288
|
|