aether-hub 1.2.6 → 1.2.8
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/commands/account.js +280 -304
- package/commands/apy.js +480 -480
- package/commands/balance.js +276 -0
- package/commands/blockhash.js +181 -0
- package/commands/broadcast.js +323 -323
- package/commands/claim.js +292 -0
- package/commands/delegations.js +45 -95
- package/commands/emergency.js +667 -657
- package/commands/epoch.js +275 -357
- package/commands/fees.js +276 -0
- package/commands/info.js +495 -536
- package/commands/monitor.js +431 -431
- package/commands/multisig.js +726 -726
- package/commands/network.js +429 -503
- package/commands/ping.js +266 -320
- package/commands/price.js +253 -253
- package/commands/sdk-test.js +477 -0
- package/commands/sdk.js +537 -537
- package/commands/slot.js +155 -0
- package/commands/snapshot.js +509 -509
- package/commands/stake-info.js +139 -0
- package/commands/stake-positions.js +31 -46
- package/commands/stats.js +418 -418
- package/commands/status.js +326 -370
- package/commands/supply.js +37 -83
- package/commands/tps.js +238 -0
- package/commands/transfer.js +495 -0
- package/commands/tx-history.js +65 -227
- package/commands/validator-info.js +10 -4
- package/commands/validator-start.js +1 -1
- package/commands/validator-status.js +32 -73
- package/commands/validators.js +36 -75
- package/commands/wallet.js +8 -29
- package/index.js +65 -8
- package/package.json +1 -3
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* aether-cli claim
|
|
4
|
+
*
|
|
5
|
+
* Claim accumulated staking rewards for a wallet.
|
|
6
|
+
* Fetches pending rewards from the chain and submits a claim transaction.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* aether claim --address <addr> [--json] [--rpc <url>]
|
|
10
|
+
*
|
|
11
|
+
* Examples:
|
|
12
|
+
* aether claim --address ATHxxx
|
|
13
|
+
* aether claim --address ATHxxx --json
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const https = require('https');
|
|
17
|
+
const http = require('http');
|
|
18
|
+
|
|
19
|
+
// ANSI colours
|
|
20
|
+
const C = {
|
|
21
|
+
reset: '\x1b[0m',
|
|
22
|
+
bright: '\x1b[1m',
|
|
23
|
+
dim: '\x1b[2m',
|
|
24
|
+
red: '\x1b[31m',
|
|
25
|
+
green: '\x1b[32m',
|
|
26
|
+
yellow: '\x1b[33m',
|
|
27
|
+
cyan: '\x1b[36m',
|
|
28
|
+
magenta: '\x1b[35m',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Config
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
function getDefaultRpc() {
|
|
36
|
+
return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// HTTP helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
function httpRequest(rpcUrl, pathStr, options = {}, timeoutMs = 8000) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const url = new URL(pathStr, rpcUrl);
|
|
46
|
+
const lib = url.protocol === 'https:' ? https : http;
|
|
47
|
+
const reqOptions = {
|
|
48
|
+
hostname: url.hostname,
|
|
49
|
+
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
50
|
+
path: url.pathname + url.search,
|
|
51
|
+
method: options.method || 'GET',
|
|
52
|
+
headers: { 'Content-Type': 'application/json', ...options.headers },
|
|
53
|
+
};
|
|
54
|
+
const req = lib.request(reqOptions, (res) => {
|
|
55
|
+
let data = '';
|
|
56
|
+
res.on('data', (chunk) => data += chunk);
|
|
57
|
+
res.on('end', () => {
|
|
58
|
+
try { resolve(JSON.parse(data)); }
|
|
59
|
+
catch { resolve(data); }
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
req.on('error', reject);
|
|
63
|
+
req.setTimeout(timeoutMs, () => {
|
|
64
|
+
req.destroy();
|
|
65
|
+
reject(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
66
|
+
});
|
|
67
|
+
if (options.body) req.write(options.body);
|
|
68
|
+
req.end();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Argument parsing
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
function parseArgs() {
|
|
77
|
+
const args = process.argv.slice(2);
|
|
78
|
+
const result = { address: null, json: false };
|
|
79
|
+
|
|
80
|
+
for (let i = 0; i < args.length; i++) {
|
|
81
|
+
if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) {
|
|
82
|
+
result.address = args[i + 1];
|
|
83
|
+
i++;
|
|
84
|
+
} else if (args[i] === '--json' || args[i] === '--json-output') {
|
|
85
|
+
result.json = true;
|
|
86
|
+
} else if (args[i] === '--rpc' && args[i + 1]) {
|
|
87
|
+
result.rpc = args[i + 1];
|
|
88
|
+
i++;
|
|
89
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
90
|
+
result.help = true;
|
|
91
|
+
} else if (args[i] === '--dry-run') {
|
|
92
|
+
result.dryRun = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Format helpers
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
function formatAether(lamports) {
|
|
104
|
+
const aeth = (lamports || 0) / 1e9;
|
|
105
|
+
return aeth.toLocaleString(undefined, { minimumFractionDigits: 4, maximumFractionDigits: 4 }) + ' AETH';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function formatFlux(lamports) {
|
|
109
|
+
const flux = (lamports || 0) / 1e6;
|
|
110
|
+
return flux.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' FLUX';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function shortPubkey(pubkey) {
|
|
114
|
+
if (!pubkey || pubkey.length < 16) return pubkey || 'unknown';
|
|
115
|
+
return pubkey.slice(0, 8) + '...' + pubkey.slice(-8);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Main
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
async function claimCommand() {
|
|
123
|
+
const opts = parseArgs();
|
|
124
|
+
|
|
125
|
+
if (opts.help) {
|
|
126
|
+
console.log(`
|
|
127
|
+
${C.bright}${C.cyan}claim${C.reset} — Claim accumulated staking rewards for a wallet
|
|
128
|
+
|
|
129
|
+
${C.bright}USAGE${C.reset}
|
|
130
|
+
aether claim --address <addr> [--json] [--rpc <url>] [--dry-run]
|
|
131
|
+
|
|
132
|
+
${C.bright}OPTIONS${C.reset}
|
|
133
|
+
--address <addr> Wallet address (ATH...)
|
|
134
|
+
--json Output raw JSON
|
|
135
|
+
--rpc <url> RPC endpoint (default: AETHER_RPC or localhost:8899)
|
|
136
|
+
--dry-run Preview claim without submitting transaction
|
|
137
|
+
--help Show this help
|
|
138
|
+
|
|
139
|
+
${C.bright}EXAMPLES${C.reset}
|
|
140
|
+
aether claim --address ATH3abc...
|
|
141
|
+
aether claim --address ATH3abc... --dry-run
|
|
142
|
+
aether claim --address ATH3abc... --json
|
|
143
|
+
`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!opts.address) {
|
|
148
|
+
console.log(` ${C.red}✗ Missing --address${C.reset}\n`);
|
|
149
|
+
console.log(` Usage: aether claim --address <addr> [--json] [--dry-run]\n`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const rpcUrl = opts.rpc || getDefaultRpc();
|
|
154
|
+
const address = opts.address;
|
|
155
|
+
const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
|
|
156
|
+
|
|
157
|
+
if (!opts.json) {
|
|
158
|
+
console.log(`\n${C.bright}${C.cyan}── Claim Staking Rewards ────────────────────────────────${C.reset}\n`);
|
|
159
|
+
console.log(` ${C.dim}Wallet:${C.reset} ${address}`);
|
|
160
|
+
console.log(` ${C.dim}RPC: ${C.reset} ${rpcUrl}`);
|
|
161
|
+
if (opts.dryRun) console.log(` ${C.yellow}(dry-run mode - no transaction will be submitted)${C.reset}`);
|
|
162
|
+
console.log();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
// Step 1: Fetch stake positions to calculate pending rewards
|
|
167
|
+
const stakeRes = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(rawAddr)}`);
|
|
168
|
+
|
|
169
|
+
let stakeAccounts = [];
|
|
170
|
+
if (Array.isArray(stakeRes)) {
|
|
171
|
+
stakeAccounts = stakeRes;
|
|
172
|
+
} else if (stakeRes && typeof stakeRes === 'object') {
|
|
173
|
+
stakeAccounts = stakeRes.accounts || stakeRes.stake_accounts || stakeRes.data || [];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!opts.json) {
|
|
177
|
+
console.log(` ${C.dim}Fetching stake positions...${C.reset}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!stakeAccounts || stakeAccounts.length === 0) {
|
|
181
|
+
console.log(` ${C.yellow}? No active stake positions found.${C.reset}`);
|
|
182
|
+
console.log(` ${C.dim} Stake AETH with: ${C.cyan}aether stake --validator <addr> --amount <aeth>${C.reset}\n`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Calculate total pending rewards
|
|
187
|
+
let totalPendingRewards = 0;
|
|
188
|
+
const rewardBreakdown = [];
|
|
189
|
+
|
|
190
|
+
for (const acc of stakeAccounts) {
|
|
191
|
+
const pendingRewards = acc.pending_rewards || acc.pendingRewards || acc.rewards || 0;
|
|
192
|
+
const stakeLamports = acc.stake_lamports || acc.lamports || 0;
|
|
193
|
+
const validator = acc.validator || acc.delegate || acc.validator_address || 'unknown';
|
|
194
|
+
|
|
195
|
+
totalPendingRewards += pendingRewards;
|
|
196
|
+
rewardBreakdown.push({
|
|
197
|
+
stakeAcct: acc.pubkey || acc.publicKey || acc.account || 'unknown',
|
|
198
|
+
validator,
|
|
199
|
+
stakeLamports,
|
|
200
|
+
pendingRewards,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!opts.json) {
|
|
205
|
+
console.log(` ${C.bright}Stake Positions (${stakeAccounts.length})${C.reset}\n`);
|
|
206
|
+
|
|
207
|
+
for (const pos of rewardBreakdown) {
|
|
208
|
+
const shortVal = shortPubkey(pos.validator);
|
|
209
|
+
const shortAcct = shortPubkey(pos.stakeAcct);
|
|
210
|
+
console.log(` ${C.dim}├─ ${C.reset}${shortAcct} → ${C.cyan}${shortVal}${C.reset}`);
|
|
211
|
+
console.log(` │ ${C.dim}Staked:${C.reset} ${formatAether(pos.stakeLamports)}`);
|
|
212
|
+
console.log(` │ ${C.green}Pending:${C.reset} ${formatFlux(pos.pendingRewards)}\n`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(` ${C.dim}────────────────────────────────────────${C.reset}`);
|
|
216
|
+
console.log(` ${C.bright}Total Pending Rewards:${C.reset} ${C.green}${formatFlux(totalPendingRewards)}${C.reset}\n`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Step 2: If not dry-run, submit claim transaction
|
|
220
|
+
if (opts.dryRun) {
|
|
221
|
+
console.log(` ${C.yellow}⚠ Dry run - not submitting claim transaction${C.reset}\n`);
|
|
222
|
+
if (opts.json) {
|
|
223
|
+
console.log(JSON.stringify({
|
|
224
|
+
wallet_address: address,
|
|
225
|
+
dry_run: true,
|
|
226
|
+
stake_count: stakeAccounts.length,
|
|
227
|
+
total_pending_flux: totalPendingRewards,
|
|
228
|
+
total_pending_aeth: (totalPendingRewards / 1e6).toFixed(2),
|
|
229
|
+
breakdown: rewardBreakdown.map(r => ({
|
|
230
|
+
stake_account: r.stakeAcct,
|
|
231
|
+
validator: r.validator,
|
|
232
|
+
pending_flux: r.pendingRewards,
|
|
233
|
+
})),
|
|
234
|
+
}, null, 2));
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Step 3: Submit claim transaction
|
|
240
|
+
if (!opts.json) {
|
|
241
|
+
console.log(` ${C.dim}Submitting claim transaction...${C.reset}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const claimBody = JSON.stringify({
|
|
245
|
+
address: rawAddr,
|
|
246
|
+
stake_accounts: rewardBreakdown.map(r => r.stakeAcct),
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const claimRes = await httpRequest(rpcUrl, '/v1/claim', {
|
|
250
|
+
method: 'POST',
|
|
251
|
+
body: claimBody,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (opts.json) {
|
|
255
|
+
console.log(JSON.stringify({
|
|
256
|
+
wallet_address: address,
|
|
257
|
+
success: !claimRes.error,
|
|
258
|
+
total_claimed_flux: claimRes.claimed || totalPendingRewards,
|
|
259
|
+
tx_signature: claimRes.signature || claimRes.txid || null,
|
|
260
|
+
block_height: claimRes.block_height || null,
|
|
261
|
+
claimed_at: new Date().toISOString(),
|
|
262
|
+
}, null, 2));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (claimRes.error) {
|
|
267
|
+
console.log(` ${C.red}✗ Claim failed:${C.reset} ${claimRes.error}\n`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log(` ${C.green}✓ Rewards claimed!${C.reset}`);
|
|
272
|
+
console.log(` ${C.dim} Amount:${C.reset} ${C.green}${formatFlux(claimRes.claimed || totalPendingRewards)}${C.reset}`);
|
|
273
|
+
if (claimRes.signature || claimRes.txid) {
|
|
274
|
+
console.log(` ${C.dim} Tx:${C.reset} ${shortPubkey(claimRes.signature || claimRes.txid)}`);
|
|
275
|
+
}
|
|
276
|
+
console.log();
|
|
277
|
+
|
|
278
|
+
} catch (err) {
|
|
279
|
+
if (opts.json) {
|
|
280
|
+
console.log(JSON.stringify({ address, error: err.message }, null, 2));
|
|
281
|
+
} else {
|
|
282
|
+
console.log(` ${C.red}✗ Failed to claim rewards:${C.reset} ${err.message}\n`);
|
|
283
|
+
}
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
module.exports = { claimCommand };
|
|
289
|
+
|
|
290
|
+
if (require.main === module) {
|
|
291
|
+
claimCommand();
|
|
292
|
+
}
|
package/commands/delegations.js
CHANGED
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
* aether delegations list --address <addr> List all stake delegations
|
|
10
10
|
* aether delegations list --address <addr> --json JSON output
|
|
11
11
|
* aether delegations claim --address <addr> --account <stakeAcct> [--json]
|
|
12
|
+
*
|
|
13
|
+
* SDK wired to: GET /v1/slot, GET /v1/account/<addr>, GET /v1/stake/<addr>
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
|
-
const
|
|
15
|
-
const https = require('https');
|
|
16
|
+
const path = require('path');
|
|
16
17
|
const readline = require('readline');
|
|
17
18
|
const crypto = require('crypto');
|
|
18
19
|
const bs58 = require('bs58').default;
|
|
@@ -32,18 +33,25 @@ const C = {
|
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const DERIVATION_PATH = "m/44'/7777777'/0'/0'";
|
|
35
|
-
const CLI_VERSION = '1.0.
|
|
36
|
+
const CLI_VERSION = '1.0.6';
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// SDK Import
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
43
|
+
const aether = require(sdkPath);
|
|
36
44
|
|
|
37
45
|
// ---------------------------------------------------------------------------
|
|
38
46
|
// Paths & config
|
|
39
47
|
// ---------------------------------------------------------------------------
|
|
40
48
|
|
|
41
49
|
function getAetherDir() {
|
|
42
|
-
return
|
|
50
|
+
return path.join(require('os').homedir(), '.aether');
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
function loadConfig() {
|
|
46
|
-
const p =
|
|
54
|
+
const p = path.join(getAetherDir(), 'config.json');
|
|
47
55
|
if (!require('fs').existsSync(p)) return { defaultWallet: null };
|
|
48
56
|
try {
|
|
49
57
|
return JSON.parse(require('fs').readFileSync(p, 'utf8'));
|
|
@@ -53,7 +61,7 @@ function loadConfig() {
|
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
function loadWallet(address) {
|
|
56
|
-
const fp =
|
|
64
|
+
const fp = path.join(getAetherDir(), 'wallets', `${address}.json`);
|
|
57
65
|
if (!require('fs').existsSync(fp)) return null;
|
|
58
66
|
return JSON.parse(require('fs').readFileSync(fp, 'utf8'));
|
|
59
67
|
}
|
|
@@ -75,57 +83,15 @@ function formatAddress(publicKey) {
|
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
// ---------------------------------------------------------------------------
|
|
78
|
-
//
|
|
86
|
+
// Config helpers
|
|
79
87
|
// ---------------------------------------------------------------------------
|
|
80
88
|
|
|
81
|
-
function
|
|
82
|
-
return
|
|
83
|
-
const url = new URL(path, rpcUrl);
|
|
84
|
-
const lib = url.protocol === 'https:' ? https : http;
|
|
85
|
-
const req = lib.request({
|
|
86
|
-
hostname: url.hostname,
|
|
87
|
-
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
88
|
-
path: url.pathname + url.search,
|
|
89
|
-
method: 'GET',
|
|
90
|
-
timeout: 8000,
|
|
91
|
-
headers: { 'Content-Type': 'application/json' },
|
|
92
|
-
}, (res) => {
|
|
93
|
-
let data = '';
|
|
94
|
-
res.on('data', (chunk) => data += chunk);
|
|
95
|
-
res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); } });
|
|
96
|
-
});
|
|
97
|
-
req.on('error', reject);
|
|
98
|
-
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
99
|
-
req.end();
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function httpPost(rpcUrl, path, body) {
|
|
104
|
-
return new Promise((resolve, reject) => {
|
|
105
|
-
const url = new URL(path, rpcUrl);
|
|
106
|
-
const lib = url.protocol === 'https:' ? https : http;
|
|
107
|
-
const bodyStr = JSON.stringify(body);
|
|
108
|
-
const req = lib.request({
|
|
109
|
-
hostname: url.hostname,
|
|
110
|
-
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
111
|
-
path: url.pathname + url.search,
|
|
112
|
-
method: 'POST',
|
|
113
|
-
timeout: 8000,
|
|
114
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(bodyStr) },
|
|
115
|
-
}, (res) => {
|
|
116
|
-
let data = '';
|
|
117
|
-
res.on('data', (chunk) => data += chunk);
|
|
118
|
-
res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); } });
|
|
119
|
-
});
|
|
120
|
-
req.on('error', reject);
|
|
121
|
-
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
122
|
-
req.write(bodyStr);
|
|
123
|
-
req.end();
|
|
124
|
-
});
|
|
89
|
+
function getDefaultRpc() {
|
|
90
|
+
return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
|
|
125
91
|
}
|
|
126
92
|
|
|
127
|
-
function
|
|
128
|
-
return
|
|
93
|
+
function createClient(rpcUrl) {
|
|
94
|
+
return new aether.AetherClient({ rpcUrl });
|
|
129
95
|
}
|
|
130
96
|
|
|
131
97
|
function formatAether(lamports) {
|
|
@@ -159,7 +125,7 @@ async function askMnemonic(rl, prompt) {
|
|
|
159
125
|
}
|
|
160
126
|
|
|
161
127
|
// ---------------------------------------------------------------------------
|
|
162
|
-
// LIST DELEGATIONS
|
|
128
|
+
// LIST DELEGATIONS — uses SDK
|
|
163
129
|
// ---------------------------------------------------------------------------
|
|
164
130
|
|
|
165
131
|
async function listDelegations(args) {
|
|
@@ -169,9 +135,9 @@ async function listDelegations(args) {
|
|
|
169
135
|
let rpcUrl = getDefaultRpc();
|
|
170
136
|
|
|
171
137
|
for (let i = 0; i < args.length; i++) {
|
|
172
|
-
if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[i
|
|
138
|
+
if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[++i];
|
|
173
139
|
else if (args[i] === '--json' || args[i] === '-j') asJson = true;
|
|
174
|
-
else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[i
|
|
140
|
+
else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[++i];
|
|
175
141
|
}
|
|
176
142
|
|
|
177
143
|
if (!address) {
|
|
@@ -186,29 +152,15 @@ async function listDelegations(args) {
|
|
|
186
152
|
return;
|
|
187
153
|
}
|
|
188
154
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// Fetch account info for context
|
|
193
|
-
const account = await httpRequest(rpcUrl, `/v1/account/${rawAddr}`);
|
|
155
|
+
const client = createClient(rpcUrl);
|
|
156
|
+
const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
|
|
194
157
|
|
|
195
|
-
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
stakeAccounts = Array.isArray(res) ? res : (res.accounts || []);
|
|
202
|
-
}
|
|
203
|
-
} catch {
|
|
204
|
-
// Fallback: try program account query
|
|
205
|
-
try {
|
|
206
|
-
const res2 = await httpRequest(rpcUrl, `/v1/program/STAKE/accounts?owner=${encodeURIComponent(rawAddr)}`);
|
|
207
|
-
if (res2 && !res2.error) {
|
|
208
|
-
stakeAccounts = Array.isArray(res2) ? res2 : (res2.accounts || []);
|
|
209
|
-
}
|
|
210
|
-
} catch { /* no stake accounts or RPC doesn't support this endpoint */ }
|
|
211
|
-
}
|
|
158
|
+
try {
|
|
159
|
+
// Real chain RPC calls via SDK
|
|
160
|
+
const [account, stakeAccounts] = await Promise.all([
|
|
161
|
+
client.getAccountInfo(rawAddr).catch(() => null),
|
|
162
|
+
client.getStakePositions(rawAddr).catch(() => []),
|
|
163
|
+
]);
|
|
212
164
|
|
|
213
165
|
if (asJson) {
|
|
214
166
|
console.log(JSON.stringify({
|
|
@@ -216,6 +168,7 @@ async function listDelegations(args) {
|
|
|
216
168
|
rpc: rpcUrl,
|
|
217
169
|
account: account && !account.error ? { lamports: account.lamports } : null,
|
|
218
170
|
delegations: stakeAccounts,
|
|
171
|
+
cli_version: CLI_VERSION,
|
|
219
172
|
fetched_at: new Date().toISOString(),
|
|
220
173
|
}, null, 2));
|
|
221
174
|
rl.close();
|
|
@@ -230,7 +183,7 @@ async function listDelegations(args) {
|
|
|
230
183
|
}
|
|
231
184
|
console.log();
|
|
232
185
|
|
|
233
|
-
if (stakeAccounts.length === 0) {
|
|
186
|
+
if (!stakeAccounts || stakeAccounts.length === 0) {
|
|
234
187
|
console.log(` ${C.dim}No stake delegations found for this wallet.${C.reset}`);
|
|
235
188
|
console.log(` ${C.dim}Delegate with:${C.reset} ${C.cyan}aether stake --address ${address} --validator <val> --amount <aeth>${C.reset}\n`);
|
|
236
189
|
rl.close();
|
|
@@ -282,7 +235,7 @@ async function listDelegations(args) {
|
|
|
282
235
|
}
|
|
283
236
|
|
|
284
237
|
// ---------------------------------------------------------------------------
|
|
285
|
-
// CLAIM REWARDS
|
|
238
|
+
// CLAIM REWARDS — uses SDK for fetch, wallet for signing
|
|
286
239
|
// ---------------------------------------------------------------------------
|
|
287
240
|
|
|
288
241
|
async function claimRewards(args) {
|
|
@@ -294,10 +247,10 @@ async function claimRewards(args) {
|
|
|
294
247
|
let rpcUrl = getDefaultRpc();
|
|
295
248
|
|
|
296
249
|
for (let i = 0; i < args.length; i++) {
|
|
297
|
-
if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[i
|
|
298
|
-
else if ((args[i] === '--account' || args[i] === '-s') && args[i + 1]) stakeAccount = args[i
|
|
250
|
+
if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[++i];
|
|
251
|
+
else if ((args[i] === '--account' || args[i] === '-s') && args[i + 1]) stakeAccount = args[++i];
|
|
299
252
|
else if (args[i] === '--json' || args[i] === '-j') asJson = true;
|
|
300
|
-
else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[i
|
|
253
|
+
else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[++i];
|
|
301
254
|
}
|
|
302
255
|
|
|
303
256
|
if (!address) {
|
|
@@ -312,17 +265,14 @@ async function claimRewards(args) {
|
|
|
312
265
|
return;
|
|
313
266
|
}
|
|
314
267
|
|
|
268
|
+
const client = createClient(rpcUrl);
|
|
269
|
+
|
|
270
|
+
// If no stake account specified, fetch list via SDK
|
|
315
271
|
if (!stakeAccount) {
|
|
316
|
-
|
|
317
|
-
let stakeAccounts = [];
|
|
318
|
-
try {
|
|
319
|
-
const res = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(address.startsWith('ATH') ? address.slice(3) : address)}`);
|
|
320
|
-
if (res && !res.error) {
|
|
321
|
-
stakeAccounts = Array.isArray(res) ? res : (res.accounts || []);
|
|
322
|
-
}
|
|
323
|
-
} catch { /* noop */ }
|
|
272
|
+
const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
|
|
273
|
+
let stakeAccounts = await client.getStakePositions(rawAddr).catch(() => []);
|
|
324
274
|
|
|
325
|
-
if (stakeAccounts.length === 0) {
|
|
275
|
+
if (!stakeAccounts || stakeAccounts.length === 0) {
|
|
326
276
|
console.log(` ${C.red}✗ No stake accounts found.${C.reset} Use ${C.cyan}--account <stakeAcct>${C.reset} to specify one.\n`);
|
|
327
277
|
rl.close();
|
|
328
278
|
return;
|
|
@@ -366,7 +316,7 @@ async function claimRewards(args) {
|
|
|
366
316
|
|
|
367
317
|
let keyPair;
|
|
368
318
|
try {
|
|
369
|
-
keyPair = deriveKeypair(mnemonic
|
|
319
|
+
keyPair = deriveKeypair(mnemonic);
|
|
370
320
|
} catch (e) {
|
|
371
321
|
console.log(` ${C.red}✗ Failed to derive keypair: ${e.message}${C.reset}\n`);
|
|
372
322
|
rl.close();
|
|
@@ -404,10 +354,10 @@ async function claimRewards(args) {
|
|
|
404
354
|
timestamp: Math.floor(Date.now() / 1000),
|
|
405
355
|
};
|
|
406
356
|
|
|
407
|
-
console.log(` ${C.dim}Submitting to ${rpcUrl}...${C.reset}`);
|
|
357
|
+
console.log(` ${C.dim}Submitting via SDK to ${rpcUrl}...${C.reset}`);
|
|
408
358
|
|
|
409
359
|
try {
|
|
410
|
-
const result = await
|
|
360
|
+
const result = await client.sendTransaction(tx);
|
|
411
361
|
|
|
412
362
|
if (result.error) {
|
|
413
363
|
console.log(`\n ${C.red}✗ Claim failed:${C.reset} ${result.error}\n`);
|