@jellylegsai/aether-cli 1.9.2 → 2.0.1
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/IMPLEMENTATION_REPORT.md +319 -0
- package/commands/blockheight.js +230 -0
- package/commands/call.js +981 -0
- package/commands/claim.js +98 -72
- package/commands/deploy.js +959 -0
- package/commands/index.js +2 -0
- package/commands/init.js +33 -49
- package/commands/network-diagnostics.js +706 -0
- package/commands/network.js +412 -429
- package/commands/rewards.js +311 -266
- package/commands/sdk.js +791 -656
- package/commands/slot.js +3 -11
- package/commands/stake.js +581 -516
- package/commands/supply.js +483 -391
- package/commands/token-accounts.js +275 -0
- package/commands/transfer.js +3 -11
- package/commands/unstake.js +3 -11
- package/commands/validator-start.js +681 -323
- package/commands/validator.js +959 -0
- package/commands/validators.js +623 -626
- package/commands/version.js +240 -0
- package/commands/wallet.js +17 -24
- package/cycle-report-issue-116.txt +165 -0
- package/index.js +501 -602
- package/lib/ui.js +623 -0
- package/package.json +10 -3
- package/sdk/index.d.ts +546 -0
- package/sdk/index.js +130 -0
- package/sdk/package.json +2 -1
package/commands/rewards.js
CHANGED
|
@@ -36,24 +36,39 @@ const nacl = require('tweetnacl');
|
|
|
36
36
|
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
37
37
|
const aether = require(sdkPath);
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
39
|
+
// Import UI Framework for consistent branding
|
|
40
|
+
const ui = require('../lib/ui');
|
|
41
|
+
const {
|
|
42
|
+
C, BRANDING, indicators,
|
|
43
|
+
success, error, warning, info,
|
|
44
|
+
code, key, value, bright, dim,
|
|
45
|
+
startSpinner, stopSpinner,
|
|
46
|
+
drawBox, drawTable,
|
|
47
|
+
progressBar, progressBarColored,
|
|
48
|
+
formatHealth
|
|
49
|
+
} = ui;
|
|
50
50
|
|
|
51
51
|
const DERIVATION_PATH = "m/44'/7777777'/0'/0'";
|
|
52
|
-
const CLI_VERSION = '
|
|
52
|
+
const CLI_VERSION = '2.0.0';
|
|
53
53
|
|
|
54
|
-
//
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// ASCII Art & Branding
|
|
56
|
+
// ============================================================================
|
|
57
|
+
|
|
58
|
+
// Helper to create section header
|
|
59
|
+
function section(title) {
|
|
60
|
+
return `\n${C.yellow}${C.bright}── ${title} ${C.reset}${C.yellow}${'─'.repeat(60 - title.length)}${C.reset}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const REWARDS_LOGO = `
|
|
64
|
+
${C.yellow} ╭────────────────────────────────────────────────────────────╮${C.reset}
|
|
65
|
+
${C.yellow} │${C.reset} ${C.bright}${C.yellow}★${C.reset} ${C.bright}STAKING REWARDS${C.reset}${' '.repeat(33)}${C.dim}v${CLI_VERSION}${C.reset} ${C.yellow}│${C.reset}
|
|
66
|
+
${C.yellow} │${C.reset} ${C.dim}Track and claim your staking rewards${C.reset}${' '.repeat(18)}${C.yellow}│${C.reset}
|
|
67
|
+
${C.yellow} ╰────────────────────────────────────────────────────────────╯${C.reset}`;
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
55
70
|
// SDK Client Setup
|
|
56
|
-
//
|
|
71
|
+
// ============================================================================
|
|
57
72
|
|
|
58
73
|
function getDefaultRpc() {
|
|
59
74
|
return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
|
|
@@ -63,33 +78,35 @@ function createClient(rpcUrl) {
|
|
|
63
78
|
return new aether.AetherClient({ rpcUrl });
|
|
64
79
|
}
|
|
65
80
|
|
|
66
|
-
//
|
|
67
|
-
// Paths &
|
|
68
|
-
//
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Paths & Config
|
|
83
|
+
// ============================================================================
|
|
69
84
|
|
|
70
85
|
function getAetherDir() {
|
|
71
86
|
return path.join(require('os').homedir(), '.aether');
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
function loadConfig() {
|
|
90
|
+
const fs = require('fs');
|
|
75
91
|
const p = path.join(getAetherDir(), 'config.json');
|
|
76
|
-
if (!
|
|
92
|
+
if (!fs.existsSync(p)) return { defaultWallet: null };
|
|
77
93
|
try {
|
|
78
|
-
return JSON.parse(
|
|
94
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
79
95
|
} catch {
|
|
80
96
|
return { defaultWallet: null };
|
|
81
97
|
}
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
function loadWallet(address) {
|
|
101
|
+
const fs = require('fs');
|
|
85
102
|
const fp = path.join(getAetherDir(), 'wallets', `${address}.json`);
|
|
86
|
-
if (!
|
|
87
|
-
return JSON.parse(
|
|
103
|
+
if (!fs.existsSync(fp)) return null;
|
|
104
|
+
return JSON.parse(fs.readFileSync(fp, 'utf8'));
|
|
88
105
|
}
|
|
89
106
|
|
|
90
|
-
//
|
|
91
|
-
// Crypto
|
|
92
|
-
//
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Crypto Helpers
|
|
109
|
+
// ============================================================================
|
|
93
110
|
|
|
94
111
|
function deriveKeypair(mnemonic) {
|
|
95
112
|
if (!bip39.validateMnemonic(mnemonic)) throw new Error('Invalid mnemonic');
|
|
@@ -109,9 +126,9 @@ function signTransaction(tx, secretKey) {
|
|
|
109
126
|
return bs58.encode(sig);
|
|
110
127
|
}
|
|
111
128
|
|
|
112
|
-
//
|
|
113
|
-
// Format
|
|
114
|
-
//
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// Format Helpers
|
|
131
|
+
// ============================================================================
|
|
115
132
|
|
|
116
133
|
function formatAether(lamports) {
|
|
117
134
|
if (!lamports || lamports === '0') return '0 AETH';
|
|
@@ -129,9 +146,17 @@ function shortAddress(addr) {
|
|
|
129
146
|
return addr.slice(0, 8) + '...' + addr.slice(-8);
|
|
130
147
|
}
|
|
131
148
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
149
|
+
function formatAPY(apyBps) {
|
|
150
|
+
if (!apyBps) return dim('—');
|
|
151
|
+
const pct = (apyBps / 100).toFixed(2);
|
|
152
|
+
if (apyBps > 500) return `${C.green}${pct}%${C.reset}`;
|
|
153
|
+
if (apyBps > 200) return `${C.yellow}${pct}%${C.reset}`;
|
|
154
|
+
return `${C.dim}${pct}%${C.reset}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Rewards Calculation via SDK (REAL RPC CALLS)
|
|
159
|
+
// ============================================================================
|
|
135
160
|
|
|
136
161
|
/**
|
|
137
162
|
* Fetch stake positions and calculate rewards using SDK
|
|
@@ -202,7 +227,7 @@ async function fetchStakeRewards(rpcUrl, stakeAddress) {
|
|
|
202
227
|
|
|
203
228
|
/**
|
|
204
229
|
* Fetch all stake accounts for a wallet using SDK
|
|
205
|
-
* REAL RPC
|
|
230
|
+
* REAL RPC: GET /v1/stake/<address>
|
|
206
231
|
*/
|
|
207
232
|
async function fetchWalletStakeAccounts(rpcUrl, walletAddress) {
|
|
208
233
|
const client = createClient(rpcUrl);
|
|
@@ -226,9 +251,9 @@ async function fetchWalletStakeAccounts(rpcUrl, walletAddress) {
|
|
|
226
251
|
}
|
|
227
252
|
}
|
|
228
253
|
|
|
229
|
-
//
|
|
230
|
-
// Rewards
|
|
231
|
-
//
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// Rewards List Command - FULLY WIRED TO SDK with UI Framework
|
|
256
|
+
// ============================================================================
|
|
232
257
|
|
|
233
258
|
async function rewardsList(args) {
|
|
234
259
|
const rpc = args.rpc || getDefaultRpc();
|
|
@@ -239,13 +264,13 @@ async function rewardsList(args) {
|
|
|
239
264
|
if (!address) {
|
|
240
265
|
const config = loadConfig();
|
|
241
266
|
const rl = createRl();
|
|
242
|
-
const answer = await question(rl, `\n${C.cyan}Enter wallet address (or press Enter for default):
|
|
267
|
+
const answer = await question(rl, `\n${C.cyan}${indicators.arrow}${C.reset} ${bright('Enter wallet address')} ${dim('(or press Enter for default)')}: `);
|
|
243
268
|
rl.close();
|
|
244
269
|
|
|
245
270
|
if (!answer.trim()) {
|
|
246
271
|
if (!config.defaultWallet) {
|
|
247
|
-
console.log(`\n${
|
|
248
|
-
console.log(` ${
|
|
272
|
+
console.log(`\n ${error('No default wallet and no address provided.')}`);
|
|
273
|
+
console.log(` ${dim('Set a default wallet:')} ${code('aether wallet default')}\n`);
|
|
249
274
|
return;
|
|
250
275
|
}
|
|
251
276
|
address = config.defaultWallet;
|
|
@@ -260,24 +285,30 @@ async function rewardsList(args) {
|
|
|
260
285
|
if (config.defaultWallet) address = config.defaultWallet;
|
|
261
286
|
}
|
|
262
287
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
288
|
+
if (!isJson) {
|
|
289
|
+
console.log(REWARDS_LOGO);
|
|
290
|
+
console.log();
|
|
291
|
+
console.log(` ${indicators.info} Wallet: ${bright(shortAddress(address))}`);
|
|
292
|
+
console.log(` ${indicators.info} RPC: ${dim(rpc)}\n`);
|
|
293
|
+
}
|
|
267
294
|
|
|
268
|
-
// Fetch stake accounts via SDK
|
|
295
|
+
// Fetch stake accounts via SDK with spinner
|
|
296
|
+
startSpinner('Fetching stake accounts');
|
|
269
297
|
const stakeAccounts = await fetchWalletStakeAccounts(rpc, address);
|
|
298
|
+
stopSpinner(true, `${stakeAccounts.length} stake account(s) found`);
|
|
270
299
|
|
|
271
300
|
if (stakeAccounts.length === 0) {
|
|
272
|
-
console.log(
|
|
273
|
-
console.log(` ${
|
|
301
|
+
console.log(`\n ${warning('No stake accounts found for this wallet.')}`);
|
|
302
|
+
console.log(` ${dim('Stake AETH first:')} ${code(`aether stake --address ${address} --validator <val> --amount <aeth>`)}\n`);
|
|
274
303
|
return;
|
|
275
304
|
}
|
|
276
305
|
|
|
277
|
-
// Fetch rewards for each stake account via SDK
|
|
306
|
+
// Fetch rewards for each stake account via SDK with spinner
|
|
307
|
+
startSpinner('Fetching rewards data');
|
|
278
308
|
const rewardsResults = await Promise.all(
|
|
279
309
|
stakeAccounts.map(sa => fetchStakeRewards(rpc, sa.address))
|
|
280
310
|
);
|
|
311
|
+
stopSpinner(true, 'Rewards data retrieved');
|
|
281
312
|
|
|
282
313
|
let totalEstimatedRewards = BigInt(0);
|
|
283
314
|
let totalPendingRewards = BigInt(0);
|
|
@@ -331,39 +362,54 @@ async function rewardsList(args) {
|
|
|
331
362
|
return;
|
|
332
363
|
}
|
|
333
364
|
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
365
|
+
// Build table data for UI framework
|
|
366
|
+
const tableRows = rows.map(r => {
|
|
367
|
+
const statusIcon = r.isActive ? indicators.success : r.deactivationEpoch ? indicators.warning : indicators.error;
|
|
368
|
+
return [
|
|
369
|
+
shortAddress(r.stakeAddress),
|
|
370
|
+
shortAddress(r.validator),
|
|
371
|
+
r.delegatedStakeFormatted,
|
|
372
|
+
r.totalRewardsFormatted,
|
|
373
|
+
formatAPY(r.apyBps),
|
|
374
|
+
statusIcon
|
|
375
|
+
];
|
|
376
|
+
});
|
|
338
377
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const delegated = r.delegatedStakeFormatted || '—';
|
|
343
|
-
const totalRew = r.totalRewardsFormatted || '—';
|
|
344
|
-
const apy = r.apyBps ? `${(r.apyBps / 100).toFixed(2)}%` : '—';
|
|
345
|
-
const statusColor = r.isActive ? C.green : r.deactivationEpoch ? C.yellow : C.red;
|
|
346
|
-
const status = r.isActive ? '●' : r.deactivationEpoch ? '○' : '✗';
|
|
378
|
+
console.log();
|
|
379
|
+
console.log(ui.section('Stake Accounts'));
|
|
380
|
+
console.log();
|
|
347
381
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
382
|
+
if (tableRows.length > 0) {
|
|
383
|
+
const headers = ['Stake Account', 'Validator', 'Delegated', 'Total Rewards', 'APY', 'Status'];
|
|
384
|
+
console.log(drawTable(headers, tableRows, {
|
|
385
|
+
headerColor: C.yellow + C.bright,
|
|
386
|
+
borderColor: C.dim
|
|
387
|
+
}));
|
|
351
388
|
}
|
|
352
389
|
|
|
353
|
-
console.log(` ${C.dim}└─────────────────────────────────────────────────────────────────────────┘${C.reset}`);
|
|
354
390
|
console.log();
|
|
355
|
-
console.log(
|
|
356
|
-
console.log(
|
|
357
|
-
console.log(` ${
|
|
358
|
-
console.log(` ${
|
|
391
|
+
console.log(ui.section('Summary'));
|
|
392
|
+
console.log();
|
|
393
|
+
console.log(` ${key('Total Delegated:')} ${value(formatAether(totalDelegatedStake))}`);
|
|
394
|
+
console.log(` ${key('Total Rewards:')} ${C.green}${formatAether(totalEstimatedRewards)}${C.reset}`);
|
|
395
|
+
console.log(` ${key('Pending Rewards:')} ${C.magenta}${formatAether(totalPendingRewards)}${C.reset}`);
|
|
396
|
+
console.log(` ${key('Active Accounts:')} ${activeCount} of ${rows.length}`);
|
|
397
|
+
console.log();
|
|
398
|
+
|
|
399
|
+
// Show claim prompt if there are pending rewards
|
|
400
|
+
if (totalPendingRewards > BigInt(0)) {
|
|
401
|
+
const pendingPct = Number(totalPendingRewards) / Number(totalEstimatedRewards) * 100;
|
|
402
|
+
console.log(` ${C.yellow}${indicators.star}${C.reset} ${bright('You have unclaimed rewards!')}`);
|
|
403
|
+
console.log(` ${progressBarColored(Number(totalPendingRewards), Number(totalEstimatedRewards), 30)}`);
|
|
404
|
+
console.log(` ${dim('Run:')} ${code(`aether rewards claim --address ${address}`)}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
359
407
|
console.log();
|
|
360
|
-
console.log(` ${C.dim}SDK Methods: getStakePositions(), getRewards(), getEpochInfo()${C.reset}`);
|
|
361
|
-
console.log(` ${C.dim}Run "aether rewards claim --address ${address}" to claim pending rewards.${C.reset}\n`);
|
|
362
408
|
}
|
|
363
409
|
|
|
364
|
-
//
|
|
365
|
-
// Rewards
|
|
366
|
-
//
|
|
410
|
+
// ============================================================================
|
|
411
|
+
// Rewards Summary Command - SDK WIRED with UI
|
|
412
|
+
// ============================================================================
|
|
367
413
|
|
|
368
414
|
async function rewardsSummary(args) {
|
|
369
415
|
const rpc = args.rpc || getDefaultRpc();
|
|
@@ -372,20 +418,24 @@ async function rewardsSummary(args) {
|
|
|
372
418
|
if (!address) {
|
|
373
419
|
const config = loadConfig();
|
|
374
420
|
if (!config.defaultWallet) {
|
|
375
|
-
console.log(
|
|
421
|
+
console.log(error('No default wallet and no address provided.'));
|
|
376
422
|
return;
|
|
377
423
|
}
|
|
378
424
|
address = config.defaultWallet;
|
|
379
425
|
}
|
|
380
426
|
|
|
381
427
|
// SDK calls
|
|
428
|
+
startSpinner('Fetching stake data');
|
|
382
429
|
const stakeAccounts = await fetchWalletStakeAccounts(rpc, address);
|
|
383
430
|
if (stakeAccounts.length === 0) {
|
|
384
|
-
|
|
431
|
+
stopSpinner(false, 'No stake accounts');
|
|
432
|
+
console.log(warning(`No stake accounts for ${shortAddress(address)}`));
|
|
385
433
|
return;
|
|
386
434
|
}
|
|
387
435
|
|
|
388
436
|
const results = await Promise.all(stakeAccounts.map(sa => fetchStakeRewards(rpc, sa.address)));
|
|
437
|
+
stopSpinner(true, 'Data retrieved');
|
|
438
|
+
|
|
389
439
|
let totalRewards = BigInt(0);
|
|
390
440
|
let totalPending = BigInt(0);
|
|
391
441
|
let totalStake = BigInt(0);
|
|
@@ -400,103 +450,28 @@ async function rewardsSummary(args) {
|
|
|
400
450
|
}
|
|
401
451
|
}
|
|
402
452
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const rpc = args.rpc || getDefaultRpc();
|
|
412
|
-
const isJson = args.json || false;
|
|
413
|
-
let address = args.address || null;
|
|
414
|
-
|
|
415
|
-
const config = loadConfig();
|
|
416
|
-
const rl = createRl();
|
|
417
|
-
|
|
418
|
-
if (!address) {
|
|
419
|
-
const ans = await question(rl, `\n${C.cyan}Enter wallet address: ${C.reset}`);
|
|
420
|
-
address = ans.trim();
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (!address) {
|
|
424
|
-
console.log(`\n${C.red}✗ No address provided.${C.reset}\n`);
|
|
425
|
-
rl.close();
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
rl.close();
|
|
430
|
-
|
|
431
|
-
// SDK calls
|
|
432
|
-
const stakeAccounts = await fetchWalletStakeAccounts(rpc, address);
|
|
433
|
-
if (stakeAccounts.length === 0) {
|
|
434
|
-
if (isJson) {
|
|
435
|
-
console.log(JSON.stringify({ address, pending: [], total_pending: '0', sdk_version: CLI_VERSION }, null, 2));
|
|
436
|
-
} else {
|
|
437
|
-
console.log(`\n${C.red}✗ No stake accounts found for ${address}${C.reset}\n`);
|
|
438
|
-
}
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const results = [];
|
|
443
|
-
let totalPending = BigInt(0);
|
|
453
|
+
// Summary box
|
|
454
|
+
const summaryContent = [
|
|
455
|
+
`${C.cyan}${shortAddress(address)}${C.reset}`,
|
|
456
|
+
`${key('Stake:')} ${value(formatAether(totalStake))}`,
|
|
457
|
+
`${key('Total Rewards:')} ${C.green}${formatAether(totalRewards)}${C.reset}`,
|
|
458
|
+
`${key('Pending:')} ${C.magenta}${formatAether(totalPending)}${C.reset}`,
|
|
459
|
+
`${key('Active:')} ${activeCount}/${results.length}`,
|
|
460
|
+
].join('\n');
|
|
444
461
|
|
|
445
|
-
// SDK calls for each stake account
|
|
446
|
-
for (const sa of stakeAccounts) {
|
|
447
|
-
const rd = await fetchStakeRewards(rpc, sa.address);
|
|
448
|
-
if (!rd.error) {
|
|
449
|
-
const pending = BigInt(rd.pendingRewards || 0);
|
|
450
|
-
totalPending += pending;
|
|
451
|
-
results.push({
|
|
452
|
-
stake_account: sa.address,
|
|
453
|
-
validator: sa.validator || rd.validator || 'unknown',
|
|
454
|
-
delegated_stake: rd.delegatedStakeFormatted || '0',
|
|
455
|
-
pending_rewards: rd.pendingRewardsFormatted || '0',
|
|
456
|
-
pending_lamports: pending.toString(),
|
|
457
|
-
apy_bps: rd.apyBps || 0,
|
|
458
|
-
is_active: rd.isActive,
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (isJson) {
|
|
464
|
-
console.log(JSON.stringify({
|
|
465
|
-
address,
|
|
466
|
-
rpc,
|
|
467
|
-
total_pending: totalPending.toString(),
|
|
468
|
-
total_pending_formatted: formatAether(totalPending.toString()),
|
|
469
|
-
accounts: results,
|
|
470
|
-
cli_version: CLI_VERSION,
|
|
471
|
-
fetched_at: new Date().toISOString(),
|
|
472
|
-
}, null, 2));
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
console.log(`\n${C.bright}${C.cyan}╔══════════════════════════════════════════════════════════════╗${C.reset}`);
|
|
477
|
-
console.log(`${C.bright}${C.cyan}║ Pending Staking Rewards (SDK-Wired) ║${C.reset}`);
|
|
478
|
-
console.log(`${C.bright}${C.cyan}╚══════════════════════════════════════════════════════════════╝${C.reset}\n`);
|
|
479
|
-
console.log(` ${C.dim}Wallet:${C.reset} ${C.bright}${address}${C.reset}`);
|
|
480
|
-
console.log(` ${C.dim}RPC:${C.reset} ${rpc}`);
|
|
481
462
|
console.log();
|
|
482
|
-
console.log(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
console.log(` ${C.dim}${'─'.repeat(72)}${C.reset}`);
|
|
491
|
-
console.log(` ${C.bright}TOTAL PENDING${C.reset.padEnd(52)} ${C.magenta}${formatAethFull(totalPending.toString()).padStart(12)}${C.reset}`);
|
|
463
|
+
console.log(drawBox(summaryContent, {
|
|
464
|
+
title: 'Rewards Summary',
|
|
465
|
+
titleColor: C.yellow,
|
|
466
|
+
borderColor: C.dim,
|
|
467
|
+
style: 'single'
|
|
468
|
+
}));
|
|
492
469
|
console.log();
|
|
493
|
-
console.log(` ${C.dim}SDK: getStakePositions(), getRewards()${C.reset}`);
|
|
494
|
-
console.log(` ${C.dim}Run ${C.cyan}aether rewards claim --address ${address}${C.dim} to claim.${C.reset}\n`);
|
|
495
470
|
}
|
|
496
471
|
|
|
497
|
-
//
|
|
498
|
-
// Rewards
|
|
499
|
-
//
|
|
472
|
+
// ============================================================================
|
|
473
|
+
// Rewards Claim Command - SDK WIRED with Enhanced UI
|
|
474
|
+
// ============================================================================
|
|
500
475
|
|
|
501
476
|
async function rewardsClaim(args) {
|
|
502
477
|
const rpc = args.rpc || getDefaultRpc();
|
|
@@ -507,30 +482,40 @@ async function rewardsClaim(args) {
|
|
|
507
482
|
const config = loadConfig();
|
|
508
483
|
const rl = createRl();
|
|
509
484
|
|
|
485
|
+
// Print header
|
|
486
|
+
if (!isJson) {
|
|
487
|
+
console.log(REWARDS_LOGO);
|
|
488
|
+
console.log();
|
|
489
|
+
}
|
|
490
|
+
|
|
510
491
|
if (!address) {
|
|
511
|
-
const ans = await question(rl,
|
|
492
|
+
const ans = await question(rl, `${C.cyan}${indicators.arrow}${C.reset} ${bright('Enter wallet address')}: `);
|
|
512
493
|
address = ans.trim();
|
|
513
494
|
}
|
|
514
495
|
|
|
515
496
|
if (!stakeAccount) {
|
|
516
497
|
// SDK call to fetch stake accounts
|
|
498
|
+
startSpinner('Fetching stake accounts');
|
|
517
499
|
const stakeAccounts = await fetchWalletStakeAccounts(rpc, address);
|
|
500
|
+
stopSpinner(true, `${stakeAccounts.length} account(s) found`);
|
|
501
|
+
|
|
518
502
|
if (stakeAccounts.length === 0) {
|
|
519
|
-
console.log(`\n${
|
|
503
|
+
console.log(`\n ${error('No stake accounts found for this wallet.')}\n`);
|
|
520
504
|
rl.close();
|
|
521
505
|
return;
|
|
522
506
|
}
|
|
523
507
|
if (stakeAccounts.length === 1) {
|
|
524
508
|
stakeAccount = stakeAccounts[0].address;
|
|
525
509
|
} else {
|
|
526
|
-
console.log(`\n${
|
|
510
|
+
console.log(`\n ${bright('Select stake account:')}`);
|
|
527
511
|
stakeAccounts.forEach((sa, i) => {
|
|
528
|
-
|
|
512
|
+
const statusIcon = sa.deactivationEpoch ? indicators.warning : indicators.success;
|
|
513
|
+
console.log(` ${C.cyan}${i + 1})${C.reset} ${statusIcon} ${shortAddress(sa.address)} ${dim('→')} ${shortAddress(sa.validator || 'unknown')}`);
|
|
529
514
|
});
|
|
530
|
-
const ans = await question(rl,
|
|
515
|
+
const ans = await question(rl, `\n${C.cyan}${indicators.arrow}${C.reset} ${bright('Enter number')}: `);
|
|
531
516
|
const idx = parseInt(ans.trim()) - 1;
|
|
532
517
|
if (idx < 0 || idx >= stakeAccounts.length) {
|
|
533
|
-
console.log(`\n${
|
|
518
|
+
console.log(`\n ${error('Invalid selection.')}\n`);
|
|
534
519
|
rl.close();
|
|
535
520
|
return;
|
|
536
521
|
}
|
|
@@ -541,42 +526,42 @@ async function rewardsClaim(args) {
|
|
|
541
526
|
// Load wallet for signing
|
|
542
527
|
const wallet = loadWallet(address);
|
|
543
528
|
if (!wallet) {
|
|
544
|
-
console.log(`\n${
|
|
545
|
-
console.log(` ${
|
|
529
|
+
console.log(`\n ${error(`Wallet not found locally: ${address}`)}`);
|
|
530
|
+
console.log(` ${dim('Import it:')} ${code('aether wallet import')}\n`);
|
|
546
531
|
rl.close();
|
|
547
532
|
return;
|
|
548
533
|
}
|
|
549
534
|
|
|
550
|
-
console.log(`\n${
|
|
551
|
-
console.log(
|
|
552
|
-
console.log(`${C.bright}${C.cyan}╚════════════════════════════════════════╝${C.reset}\n`);
|
|
553
|
-
console.log(` ${C.dim}Wallet:${C.reset} ${address}`);
|
|
554
|
-
console.log(` ${C.dim}Stake Account:${C.reset} ${stakeAccount}`);
|
|
535
|
+
console.log(`\n ${key('Wallet:')} ${address}`);
|
|
536
|
+
console.log(` ${key('Stake Account:')} ${stakeAccount}`);
|
|
555
537
|
|
|
556
538
|
// SDK call to fetch current rewards
|
|
539
|
+
startSpinner('Fetching rewards data');
|
|
557
540
|
const client = createClient(rpc);
|
|
558
541
|
const rewardData = await fetchStakeRewards(rpc, stakeAccount);
|
|
542
|
+
stopSpinner(true, 'Rewards data retrieved');
|
|
543
|
+
|
|
559
544
|
if (rewardData.error) {
|
|
560
|
-
console.log(`\n${
|
|
545
|
+
console.log(`\n ${error(`Failed to fetch stake account: ${rewardData.error}`)}\n`);
|
|
561
546
|
rl.close();
|
|
562
547
|
return;
|
|
563
548
|
}
|
|
564
549
|
|
|
565
|
-
console.log(` ${
|
|
566
|
-
console.log(` ${
|
|
567
|
-
console.log(` ${
|
|
568
|
-
console.log(` ${
|
|
550
|
+
console.log(` ${key('Delegated Stake:')} ${rewardData.delegatedStakeFormatted}`);
|
|
551
|
+
console.log(` ${key('Est. Pending Rewards:')} ${C.green}${rewardData.pendingRewardsFormatted}${C.reset}`);
|
|
552
|
+
console.log(` ${key('Validator:')} ${shortAddress(rewardData.validator)}`);
|
|
553
|
+
console.log(` ${key('APY:')} ${formatAPY(rewardData.apyBps)}`);
|
|
569
554
|
|
|
570
555
|
const pendingRewards = BigInt(rewardData.pendingRewards || 0);
|
|
571
556
|
if (pendingRewards === BigInt(0)) {
|
|
572
|
-
console.log(`\n${
|
|
557
|
+
console.log(`\n ${warning('No rewards accumulated yet.')}\n`);
|
|
573
558
|
rl.close();
|
|
574
559
|
return;
|
|
575
560
|
}
|
|
576
561
|
|
|
577
|
-
const confirm = await question(rl, `\n ${C.yellow}Claim ${rewardData.pendingRewardsFormatted}? [y/N]
|
|
562
|
+
const confirm = await question(rl, `\n ${C.yellow}${indicators.warning}${C.reset} ${bright('Claim')} ${C.green}${rewardData.pendingRewardsFormatted}${C.reset}${bright('?')} ${dim('[y/N]')}: `);
|
|
578
563
|
if (confirm.trim().toLowerCase() !== 'y') {
|
|
579
|
-
console.log(
|
|
564
|
+
console.log(` ${dim('Cancelled.')}\n`);
|
|
580
565
|
rl.close();
|
|
581
566
|
return;
|
|
582
567
|
}
|
|
@@ -584,20 +569,25 @@ async function rewardsClaim(args) {
|
|
|
584
569
|
// Ask for mnemonic to derive signing keypair
|
|
585
570
|
let keypair;
|
|
586
571
|
try {
|
|
587
|
-
|
|
572
|
+
console.log();
|
|
573
|
+
const mnemonic = await askMnemonic(rl, `${bright('Enter your 12/24-word passphrase')} ${dim('to sign the claim')}`);
|
|
574
|
+
startSpinner('Deriving keypair');
|
|
588
575
|
keypair = deriveKeypair(mnemonic);
|
|
589
576
|
|
|
590
577
|
// Verify derived address matches
|
|
591
578
|
const derivedAddress = formatAddress(keypair.publicKey);
|
|
592
579
|
if (derivedAddress !== address) {
|
|
593
|
-
|
|
594
|
-
console.log(
|
|
595
|
-
console.log(` ${
|
|
580
|
+
stopSpinner(false, 'Passphrase mismatch');
|
|
581
|
+
console.log(`\n ${error('Passphrase mismatch!')}`);
|
|
582
|
+
console.log(` ${key('Derived:')} ${derivedAddress}`);
|
|
583
|
+
console.log(` ${key('Expected:')} ${address}\n`);
|
|
596
584
|
rl.close();
|
|
597
585
|
return;
|
|
598
586
|
}
|
|
587
|
+
stopSpinner(true, 'Keypair verified');
|
|
599
588
|
} catch (err) {
|
|
600
|
-
|
|
589
|
+
stopSpinner(false, 'Failed');
|
|
590
|
+
console.log(`\n ${error(`Failed to derive keypair: ${err.message}`)}\n`);
|
|
601
591
|
rl.close();
|
|
602
592
|
return;
|
|
603
593
|
}
|
|
@@ -621,11 +611,13 @@ async function rewardsClaim(args) {
|
|
|
621
611
|
// Sign transaction
|
|
622
612
|
tx.signature = signTransaction(tx, keypair.secretKey);
|
|
623
613
|
|
|
624
|
-
console.log(`\n ${
|
|
614
|
+
console.log(`\n ${dim('Submitting transaction via SDK...')}`);
|
|
615
|
+
startSpinner('Sending to blockchain');
|
|
625
616
|
|
|
626
617
|
// SDK call: sendTransaction (REAL RPC POST /v1/transaction)
|
|
627
618
|
try {
|
|
628
619
|
const result = await client.sendTransaction(tx);
|
|
620
|
+
stopSpinner(true, 'Transaction submitted');
|
|
629
621
|
|
|
630
622
|
if (result.error) {
|
|
631
623
|
throw new Error(result.error.message || JSON.stringify(result.error));
|
|
@@ -645,28 +637,38 @@ async function rewardsClaim(args) {
|
|
|
645
637
|
timestamp: new Date().toISOString(),
|
|
646
638
|
}, null, 2));
|
|
647
639
|
} else {
|
|
648
|
-
console.log(
|
|
649
|
-
console.log(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
640
|
+
console.log();
|
|
641
|
+
console.log(drawBox([
|
|
642
|
+
`${success('Rewards claimed successfully!')}`,
|
|
643
|
+
``,
|
|
644
|
+
`${key('TX Signature:')} ${C.cyan}${result.signature || result.txid}${C.reset}`,
|
|
645
|
+
`${key('Amount Claimed:')} ${C.green}${rewardData.pendingRewardsFormatted}${C.reset}`,
|
|
646
|
+
`${key('Slot:')} ${result.slot}`,
|
|
647
|
+
`${key('SDK:')} ${dim('sendTransaction()')}`,
|
|
648
|
+
].join('\n'), {
|
|
649
|
+
title: 'Transaction Success',
|
|
650
|
+
titleColor: C.green,
|
|
651
|
+
borderColor: C.dim,
|
|
652
|
+
style: 'single'
|
|
653
|
+
}));
|
|
654
|
+
console.log(` ${dim('Check balance:')} ${code(`aether wallet balance --address ${address}`)}\n`);
|
|
654
655
|
}
|
|
655
656
|
} catch (err) {
|
|
657
|
+
stopSpinner(false, 'Transaction failed');
|
|
656
658
|
if (isJson) {
|
|
657
659
|
console.log(JSON.stringify({ success: false, error: err.message, address, stake_account: stakeAccount }, null, 2));
|
|
658
660
|
} else {
|
|
659
|
-
console.log(`\n${
|
|
660
|
-
console.log(` ${
|
|
661
|
+
console.log(`\n ${error(`Failed to submit claim: ${err.message}`)}`);
|
|
662
|
+
console.log(` ${dim('The rewards are accumulated on-chain and can be claimed later.')}\n`);
|
|
661
663
|
}
|
|
662
664
|
}
|
|
663
665
|
|
|
664
666
|
rl.close();
|
|
665
667
|
}
|
|
666
668
|
|
|
667
|
-
//
|
|
668
|
-
// Rewards
|
|
669
|
-
//
|
|
669
|
+
// ============================================================================
|
|
670
|
+
// Rewards Compound Command - SDK WIRED with UI
|
|
671
|
+
// ============================================================================
|
|
670
672
|
|
|
671
673
|
async function rewardsCompound(args) {
|
|
672
674
|
const rpc = args.rpc || getDefaultRpc();
|
|
@@ -677,13 +679,19 @@ async function rewardsCompound(args) {
|
|
|
677
679
|
const config = loadConfig();
|
|
678
680
|
const rl = createRl();
|
|
679
681
|
|
|
682
|
+
if (!isJson) {
|
|
683
|
+
console.log(REWARDS_LOGO);
|
|
684
|
+
console.log();
|
|
685
|
+
console.log(` ${C.yellow}${indicators.star}${C.reset} ${bright('Compound Mode')}: Claim and auto-restake rewards\n`);
|
|
686
|
+
}
|
|
687
|
+
|
|
680
688
|
if (!address) {
|
|
681
|
-
const ans = await question(rl,
|
|
689
|
+
const ans = await question(rl, `${C.cyan}${indicators.arrow}${C.reset} ${bright('Enter wallet address')}: `);
|
|
682
690
|
address = ans.trim();
|
|
683
691
|
}
|
|
684
692
|
|
|
685
693
|
if (!address) {
|
|
686
|
-
console.log(`\n${
|
|
694
|
+
console.log(`\n ${error('No address provided.')}\n`);
|
|
687
695
|
rl.close();
|
|
688
696
|
return;
|
|
689
697
|
}
|
|
@@ -691,16 +699,19 @@ async function rewardsCompound(args) {
|
|
|
691
699
|
// Load wallet for signing
|
|
692
700
|
const wallet = loadWallet(address);
|
|
693
701
|
if (!wallet) {
|
|
694
|
-
console.log(`\n${
|
|
695
|
-
console.log(` ${
|
|
702
|
+
console.log(`\n ${error(`Wallet not found locally: ${address}`)}`);
|
|
703
|
+
console.log(` ${dim('Import it:')} ${code('aether wallet import')}\n`);
|
|
696
704
|
rl.close();
|
|
697
705
|
return;
|
|
698
706
|
}
|
|
699
707
|
|
|
700
708
|
// SDK call to fetch stake accounts
|
|
709
|
+
startSpinner('Fetching stake accounts');
|
|
701
710
|
let stakeAccounts = await fetchWalletStakeAccounts(rpc, address);
|
|
711
|
+
stopSpinner(true, `${stakeAccounts.length} account(s) found`);
|
|
712
|
+
|
|
702
713
|
if (stakeAccounts.length === 0) {
|
|
703
|
-
console.log(`\n${
|
|
714
|
+
console.log(`\n ${error('No stake accounts found for this wallet.')}\n`);
|
|
704
715
|
rl.close();
|
|
705
716
|
return;
|
|
706
717
|
}
|
|
@@ -709,37 +720,39 @@ async function rewardsCompound(args) {
|
|
|
709
720
|
if (stakeAccount) {
|
|
710
721
|
stakeAccounts = stakeAccounts.filter(sa => sa.address === stakeAccount);
|
|
711
722
|
if (stakeAccounts.length === 0) {
|
|
712
|
-
console.log(`\n${
|
|
723
|
+
console.log(`\n ${error(`Stake account not found: ${stakeAccount}`)}\n`);
|
|
713
724
|
rl.close();
|
|
714
725
|
return;
|
|
715
726
|
}
|
|
716
727
|
}
|
|
717
728
|
|
|
718
|
-
console.log(`\n${
|
|
719
|
-
console.log(
|
|
720
|
-
console.log(
|
|
721
|
-
console.log(` ${C.dim}Wallet:${C.reset} ${C.bright}${address}${C.reset}`);
|
|
722
|
-
console.log(` ${C.dim}RPC:${C.reset} ${rpc}`);
|
|
723
|
-
console.log(` ${C.dim}Stake accounts to process:${C.reset} ${stakeAccounts.length}\n`);
|
|
729
|
+
console.log(`\n ${key('Wallet:')} ${bright(address)}`);
|
|
730
|
+
console.log(` ${key('RPC:')} ${dim(rpc)}`);
|
|
731
|
+
console.log(` ${key('Accounts to process:')} ${stakeAccounts.length}\n`);
|
|
724
732
|
|
|
725
733
|
// Ask for mnemonic upfront
|
|
726
|
-
console.log(
|
|
734
|
+
console.log(` ${C.yellow}${indicators.warning}${C.reset} ${bright('Compound requires your wallet passphrase to sign transactions')}`);
|
|
727
735
|
let keypair;
|
|
728
736
|
try {
|
|
729
|
-
|
|
737
|
+
console.log();
|
|
738
|
+
const mnemonic = await askMnemonic(rl, `${bright('Enter your 12/24-word passphrase')}`);
|
|
739
|
+
startSpinner('Deriving keypair');
|
|
730
740
|
keypair = deriveKeypair(mnemonic);
|
|
731
741
|
|
|
732
742
|
// Verify address matches
|
|
733
743
|
const derivedAddress = formatAddress(keypair.publicKey);
|
|
734
744
|
if (derivedAddress !== address) {
|
|
735
|
-
|
|
736
|
-
console.log(
|
|
737
|
-
console.log(` ${
|
|
745
|
+
stopSpinner(false, 'Passphrase mismatch');
|
|
746
|
+
console.log(`\n ${error('Passphrase mismatch.')}`);
|
|
747
|
+
console.log(` ${key('Derived:')} ${derivedAddress}`);
|
|
748
|
+
console.log(` ${key('Expected:')} ${address}\n`);
|
|
738
749
|
rl.close();
|
|
739
750
|
return;
|
|
740
751
|
}
|
|
752
|
+
stopSpinner(true, 'Keypair verified');
|
|
741
753
|
} catch (err) {
|
|
742
|
-
|
|
754
|
+
stopSpinner(false, 'Failed');
|
|
755
|
+
console.log(`\n ${error(`Failed to derive keypair: ${err.message}`)}\n`);
|
|
743
756
|
rl.close();
|
|
744
757
|
return;
|
|
745
758
|
}
|
|
@@ -749,26 +762,29 @@ async function rewardsCompound(args) {
|
|
|
749
762
|
let totalCompounded = BigInt(0);
|
|
750
763
|
let successCount = 0;
|
|
751
764
|
|
|
752
|
-
|
|
753
|
-
|
|
765
|
+
console.log(`\n ${bright('Processing stake accounts...')}\n`);
|
|
766
|
+
|
|
767
|
+
for (let i = 0; i < stakeAccounts.length; i++) {
|
|
768
|
+
const sa = stakeAccounts[i];
|
|
769
|
+
console.log(` ${dim(`[${i + 1}/${stakeAccounts.length}]`)} ${shortAddress(sa.address)}`);
|
|
754
770
|
|
|
755
771
|
try {
|
|
756
772
|
// SDK call to fetch rewards
|
|
757
773
|
const rewardData = await fetchStakeRewards(rpc, sa.address);
|
|
758
774
|
if (rewardData.error) {
|
|
759
|
-
console.log(`
|
|
775
|
+
console.log(` ${error(`Failed to fetch: ${rewardData.error}`)}`);
|
|
760
776
|
compoundResults.push({ stake_account: sa.address, status: 'error', error: rewardData.error });
|
|
761
777
|
continue;
|
|
762
778
|
}
|
|
763
779
|
|
|
764
780
|
const estimatedRewards = BigInt(rewardData.pendingRewards || 0);
|
|
765
781
|
if (estimatedRewards === BigInt(0)) {
|
|
766
|
-
console.log(`
|
|
782
|
+
console.log(` ${warning('No rewards to compound')}`);
|
|
767
783
|
compoundResults.push({ stake_account: sa.address, status: 'no_rewards', rewards: '0' });
|
|
768
784
|
continue;
|
|
769
785
|
}
|
|
770
786
|
|
|
771
|
-
console.log(`
|
|
787
|
+
console.log(` ${dim('Rewards:')} ${C.green}${rewardData.pendingRewardsFormatted}${C.reset} ${dim('→')} ${shortAddress(sa.validator || rewardData.validator || 'unknown')}`);
|
|
772
788
|
|
|
773
789
|
// Build compound transaction (ClaimRewards + Stake in one)
|
|
774
790
|
const tx = {
|
|
@@ -790,11 +806,13 @@ async function rewardsCompound(args) {
|
|
|
790
806
|
// Sign transaction
|
|
791
807
|
tx.signature = signTransaction(tx, keypair.secretKey);
|
|
792
808
|
|
|
809
|
+
process.stdout.write(` ${dim('Submitting...')}`);
|
|
810
|
+
|
|
793
811
|
// SDK call: sendTransaction
|
|
794
812
|
const result = await client.sendTransaction(tx);
|
|
795
813
|
|
|
796
814
|
if (result.signature || result.txid || result.success) {
|
|
797
|
-
|
|
815
|
+
process.stdout.write(`\r ${success('Compounded')}\n`);
|
|
798
816
|
totalCompounded += estimatedRewards;
|
|
799
817
|
successCount++;
|
|
800
818
|
compoundResults.push({
|
|
@@ -805,26 +823,26 @@ async function rewardsCompound(args) {
|
|
|
805
823
|
tx: result.signature || result.txid,
|
|
806
824
|
});
|
|
807
825
|
} else {
|
|
808
|
-
|
|
826
|
+
process.stdout.write(`\r ${error(`Failed: ${result.error || 'Unknown error'}`)}\n`);
|
|
809
827
|
compoundResults.push({ stake_account: sa.address, status: 'failed', error: result.error });
|
|
810
828
|
}
|
|
811
829
|
} catch (err) {
|
|
812
|
-
|
|
830
|
+
process.stdout.write(`\r ${error(`Error: ${err.message}`)}\n`);
|
|
813
831
|
compoundResults.push({ stake_account: sa.address, status: 'error', error: err.message });
|
|
814
832
|
}
|
|
815
|
-
console.log();
|
|
816
833
|
}
|
|
817
834
|
|
|
818
835
|
rl.close();
|
|
819
836
|
|
|
820
837
|
// Summary
|
|
821
|
-
console.log(
|
|
822
|
-
console.log(
|
|
823
|
-
console.log(
|
|
824
|
-
console.log(` ${
|
|
825
|
-
console.log(` ${
|
|
826
|
-
console.log(` ${
|
|
827
|
-
console.log(` ${
|
|
838
|
+
console.log();
|
|
839
|
+
console.log(ui.section('Compound Summary'));
|
|
840
|
+
console.log();
|
|
841
|
+
console.log(` ${key('Accounts processed:')} ${stakeAccounts.length}`);
|
|
842
|
+
console.log(` ${success('Successful:')} ${successCount}`);
|
|
843
|
+
console.log(` ${key('Total compounded:')} ${C.green}${formatAether(totalCompounded.toString())}${C.reset}`);
|
|
844
|
+
console.log(` ${key('SDK:')} ${dim('getStakePositions(), getRewards(), sendTransaction()')}`);
|
|
845
|
+
console.log();
|
|
828
846
|
|
|
829
847
|
if (isJson) {
|
|
830
848
|
console.log(JSON.stringify({
|
|
@@ -841,9 +859,9 @@ async function rewardsCompound(args) {
|
|
|
841
859
|
}
|
|
842
860
|
}
|
|
843
861
|
|
|
844
|
-
//
|
|
845
|
-
// Parse CLI
|
|
846
|
-
//
|
|
862
|
+
// ============================================================================
|
|
863
|
+
// Parse CLI Args
|
|
864
|
+
// ============================================================================
|
|
847
865
|
|
|
848
866
|
function parseArgs() {
|
|
849
867
|
const rawArgs = process.argv.slice(3);
|
|
@@ -879,18 +897,50 @@ function question(rl, q) {
|
|
|
879
897
|
}
|
|
880
898
|
|
|
881
899
|
async function askMnemonic(rl, prompt) {
|
|
882
|
-
console.log(`\n${C.cyan}${
|
|
883
|
-
console.log(
|
|
884
|
-
const raw = await question(rl, ` >
|
|
900
|
+
console.log(`\n ${C.cyan}${indicators.info}${C.reset} ${prompt}`);
|
|
901
|
+
console.log(` ${dim('Enter your 12 or 24-word passphrase:')}`);
|
|
902
|
+
const raw = await question(rl, ` > `);
|
|
885
903
|
return raw.trim().toLowerCase();
|
|
886
904
|
}
|
|
887
905
|
|
|
888
|
-
//
|
|
889
|
-
//
|
|
890
|
-
//
|
|
906
|
+
// ============================================================================
|
|
907
|
+
// Help Display
|
|
908
|
+
// ============================================================================
|
|
909
|
+
|
|
910
|
+
function showHelp() {
|
|
911
|
+
console.log();
|
|
912
|
+
console.log(BRANDING.logoCompact);
|
|
913
|
+
console.log();
|
|
914
|
+
console.log(formatHelp(
|
|
915
|
+
'aether rewards',
|
|
916
|
+
'View and claim staking rewards earned from delegated stake accounts.',
|
|
917
|
+
'aether rewards <command> [options]',
|
|
918
|
+
[
|
|
919
|
+
{ flag: 'list', desc: 'List all rewards per stake account (default)' },
|
|
920
|
+
{ flag: 'summary', desc: 'One-line summary of total rewards' },
|
|
921
|
+
{ flag: 'claim', desc: 'Claim accumulated rewards' },
|
|
922
|
+
{ flag: 'compound', desc: 'Claim and auto-restake rewards' },
|
|
923
|
+
{ flag: '--address, -a <addr>', desc: 'Wallet address' },
|
|
924
|
+
{ flag: '--account, -s <acct>', desc: 'Specific stake account' },
|
|
925
|
+
{ flag: '--rpc <url>', desc: 'Custom RPC endpoint' },
|
|
926
|
+
{ flag: '--json, -j', desc: 'Output as JSON' },
|
|
927
|
+
],
|
|
928
|
+
[
|
|
929
|
+
{ cmd: 'aether rewards list --address ATH...', desc: 'List all rewards' },
|
|
930
|
+
{ cmd: 'aether rewards claim --address ATH...', desc: 'Claim all pending rewards' },
|
|
931
|
+
{ cmd: 'aether rewards compound --address ATH...', desc: 'Compound rewards' },
|
|
932
|
+
]
|
|
933
|
+
));
|
|
934
|
+
console.log(` ${success('Fully wired to @jellylegsai/aether-sdk')}`);
|
|
935
|
+
console.log(` ${dim('SDK: getStakePositions(), getRewards(), getEpochInfo(), sendTransaction()')}\n`);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// ============================================================================
|
|
939
|
+
// Main Entry Point
|
|
940
|
+
// ============================================================================
|
|
891
941
|
|
|
892
|
-
async function main() {
|
|
893
|
-
const args = parseArgs();
|
|
942
|
+
async function main(customArgs) {
|
|
943
|
+
const args = customArgs || parseArgs();
|
|
894
944
|
|
|
895
945
|
switch (args.subcmd) {
|
|
896
946
|
case 'list':
|
|
@@ -899,33 +949,28 @@ async function main() {
|
|
|
899
949
|
case 'summary':
|
|
900
950
|
await rewardsSummary(args);
|
|
901
951
|
break;
|
|
902
|
-
case 'pending':
|
|
903
|
-
await rewardsPending(args);
|
|
904
|
-
break;
|
|
905
952
|
case 'claim':
|
|
906
953
|
await rewardsClaim(args);
|
|
907
954
|
break;
|
|
908
955
|
case 'compound':
|
|
909
956
|
await rewardsCompound(args);
|
|
910
957
|
break;
|
|
958
|
+
case 'help':
|
|
959
|
+
case '--help':
|
|
960
|
+
case '-h':
|
|
961
|
+
showHelp();
|
|
962
|
+
break;
|
|
911
963
|
default:
|
|
912
|
-
console.log(`\n${
|
|
913
|
-
console.log(` aether rewards
|
|
914
|
-
console.log(` aether rewards summary --address <addr> One-line rewards summary`);
|
|
915
|
-
console.log(` aether rewards pending --address <addr> Show pending rewards`);
|
|
916
|
-
console.log(` aether rewards claim --address <addr> [--account <stakeAcct>] Claim rewards`);
|
|
917
|
-
console.log(` aether rewards compound --address <addr> [--account <stakeAcct>] Claim and re-stake`);
|
|
918
|
-
console.log();
|
|
919
|
-
console.log(` ${C.dim}--json Output as JSON`);
|
|
920
|
-
console.log(` --rpc <url> Use specific RPC endpoint${C.reset}`);
|
|
921
|
-
console.log();
|
|
922
|
-
console.log(` ${C.green}✓ Fully wired to @jellylegsai/aether-sdk${C.reset}`);
|
|
923
|
-
console.log(` ${C.dim}SDK: getStakePositions(), getRewards(), getEpochInfo(), sendTransaction()${C.reset}\n`);
|
|
964
|
+
console.log(`\n ${error(`Unknown command: ${args.subcmd}`)}`);
|
|
965
|
+
console.log(` ${dim('Run')} ${code('aether rewards help')} ${dim('for usage information.')}\n`);
|
|
924
966
|
}
|
|
925
967
|
}
|
|
926
968
|
|
|
927
|
-
main
|
|
928
|
-
|
|
929
|
-
|
|
969
|
+
// Run main only if executed directly
|
|
970
|
+
if (require.main === module) {
|
|
971
|
+
main().catch(err => {
|
|
972
|
+
console.error(`\n ${error('Error running rewards command:')} ${err.message}\n`);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
930
975
|
|
|
931
|
-
module.exports = { rewardsCommand: main };
|
|
976
|
+
module.exports = { rewardsCommand: main, rewardsList, rewardsSummary, rewardsClaim, rewardsCompound };
|