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.
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aether-cli - Stake Info Command
4
+ * Get staking information for an address using real chain RPC calls.
5
+ * All calls go through @jellylegsai/aether-sdk → AetherClient → real HTTP RPC.
6
+ *
7
+ * Usage:
8
+ * aether stake-info <address> Show stake info for address
9
+ * aether stake-info <address> --json JSON output
10
+ * aether stake-info <address> --rpc <url> Custom RPC endpoint
11
+ *
12
+ * SDK wired to: GET /v1/slot, GET /v1/account/<addr>, GET /v1/blockheight
13
+ */
14
+
15
+ const path = require('path');
16
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
17
+ const { AetherClient } = require(sdkPath);
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
+ // Argument parsing
33
+ // ---------------------------------------------------------------------------
34
+
35
+ function parseArgs() {
36
+ const args = process.argv.slice(2);
37
+ const result = { address: null, json: false, rpc: null };
38
+
39
+ for (let i = 0; i < args.length; i++) {
40
+ if (!args[i].startsWith('-') && !result.address) {
41
+ result.address = args[i];
42
+ } else if (args[i] === '--json' || args[i] === '-j') {
43
+ result.json = true;
44
+ } else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) {
45
+ result.rpc = args[++i];
46
+ } else if (args[i] === '--help' || args[i] === '-h') {
47
+ result.help = true;
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+
53
+ function getDefaultRpc() {
54
+ return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
55
+ }
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Main
59
+ // ---------------------------------------------------------------------------
60
+
61
+ async function stakeInfoCommand() {
62
+ const opts = parseArgs();
63
+
64
+ if (opts.help || !opts.address) {
65
+ console.log(`
66
+ ${C.bright}${C.cyan}aether-cli stake-info${C.reset} — Get stake/account info for an address
67
+
68
+ ${C.bright}USAGE${C.reset}
69
+ aether stake-info <address> [--json] [--rpc <url>]
70
+
71
+ ${C.bright}OPTIONS${C.reset}
72
+ --json, -j Output raw JSON
73
+ --rpc <url> RPC endpoint (default: AETHER_RPC or localhost:8899)
74
+ --help, -h Show this help
75
+
76
+ ${C.bright}SDK METHODS USED${C.reset}
77
+ client.getSlot() → GET /v1/slot
78
+ client.getAccountInfo(addr) → GET /v1/account/<addr>
79
+ client.getBlockHeight() → GET /v1/blockheight
80
+
81
+ ${C.bright}EXAMPLE${C.reset}
82
+ aether stake-info ATH3abc...def
83
+ `);
84
+ return;
85
+ }
86
+
87
+ const rpcUrl = opts.rpc || getDefaultRpc();
88
+ const client = new AetherClient({ rpcUrl });
89
+
90
+ try {
91
+ // Real chain RPC calls — all parallel for speed
92
+ const [slot, accountInfo, blockHeight] = await Promise.all([
93
+ client.getSlot().catch(() => null),
94
+ client.getAccountInfo(opts.address).catch(() => null),
95
+ client.getBlockHeight().catch(() => null),
96
+ ]);
97
+
98
+ const balance = accountInfo?.lamports != null
99
+ ? (accountInfo.lamports / 1e9).toFixed(4) + ' AETH'
100
+ : 'unavailable';
101
+ const owner = accountInfo?.owner || 'unknown';
102
+ const executable = accountInfo?.executable ? 'yes' : 'no';
103
+
104
+ if (opts.json) {
105
+ console.log(JSON.stringify({
106
+ address: opts.address,
107
+ slot: slot ?? null,
108
+ block_height: blockHeight ?? null,
109
+ account: {
110
+ lamports: accountInfo?.lamports ?? null,
111
+ balance_aeth: accountInfo?.lamports != null ? (accountInfo.lamports / 1e9).toFixed(4) : null,
112
+ owner: accountInfo?.owner ?? null,
113
+ executable: accountInfo?.executable ?? false,
114
+ rent_epoch: accountInfo?.rent_epoch ?? null,
115
+ },
116
+ rpc: rpcUrl,
117
+ timestamp: new Date().toISOString(),
118
+ }, null, 2));
119
+ return;
120
+ }
121
+
122
+ console.log(`\n${C.bright}${C.cyan}── Aether Stake Info ─────────────────────────────────${C.reset}\n`);
123
+ console.log(` ${C.dim}Address:${C.reset} ${opts.address}`);
124
+ console.log(` ${C.dim}Balance:${C.reset} ${C.green}${balance}${C.reset}`);
125
+ console.log(` ${C.dim}Owner:${C.reset} ${owner}`);
126
+ console.log(` ${C.dim}Executable:${C.reset} ${executable}`);
127
+ console.log(` ${C.dim}Slot:${C.reset} ${slot ?? 'unavailable'}`);
128
+ console.log(` ${C.dim}Block Height:${C.reset} ${blockHeight ?? 'unavailable'}`);
129
+ console.log(` ${C.dim}RPC:${C.reset} ${rpcUrl}\n`);
130
+ console.log(` ${C.green}? Real chain RPC calls completed${C.reset}\n`);
131
+ } catch (error) {
132
+ console.log(` ${C.red}? Error: ${error.message}${C.reset}\n`);
133
+ process.exit(1);
134
+ }
135
+ }
136
+
137
+ stakeInfoCommand();
138
+
139
+ module.exports = { stakeInfoCommand };
@@ -12,10 +12,15 @@
12
12
  * Examples:
13
13
  * aether stake-positions --address ATHxxx
14
14
  * aether wallet stake-positions --address ATHxxx --json
15
+ *
16
+ * SDK wired to: GET /v1/slot, GET /v1/stake/<address>, GET /v1/account/<addr>
15
17
  */
16
18
 
17
- const https = require('https');
18
- const http = require('http');
19
+ const path = require('path');
20
+
21
+ // Import SDK — all network calls go through @jellylegsai/aether-sdk
22
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
23
+ const aether = require(sdkPath);
19
24
 
20
25
  // ANSI colours
21
26
  const C = {
@@ -29,45 +34,18 @@ const C = {
29
34
  magenta: '\x1b[35m',
30
35
  };
31
36
 
32
- const CLI_VERSION = '1.0.0';
37
+ const CLI_VERSION = '1.0.1';
33
38
 
34
39
  // ---------------------------------------------------------------------------
35
40
  // Config
36
41
  // ---------------------------------------------------------------------------
37
42
 
38
43
  function getDefaultRpc() {
39
- return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
44
+ return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
40
45
  }
41
46
 
42
- // ---------------------------------------------------------------------------
43
- // HTTP helpers
44
- // ---------------------------------------------------------------------------
45
-
46
- function httpRequest(rpcUrl, pathStr, timeoutMs = 8000) {
47
- return new Promise((resolve, reject) => {
48
- const url = new URL(pathStr, rpcUrl);
49
- const lib = url.protocol === 'https:' ? https : http;
50
- const req = lib.request({
51
- hostname: url.hostname,
52
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
53
- path: url.pathname + url.search,
54
- method: 'GET',
55
- headers: { 'Content-Type': 'application/json' },
56
- }, (res) => {
57
- let data = '';
58
- res.on('data', (chunk) => data += chunk);
59
- res.on('end', () => {
60
- try { resolve(JSON.parse(data)); }
61
- catch { resolve(data); }
62
- });
63
- });
64
- req.on('error', reject);
65
- req.setTimeout(timeoutMs, () => {
66
- req.destroy();
67
- reject(new Error(`Request timeout after ${timeoutMs}ms`));
68
- });
69
- req.end();
70
- });
47
+ function createClient(rpcUrl) {
48
+ return new aether.AetherClient({ rpcUrl });
71
49
  }
72
50
 
73
51
  // ---------------------------------------------------------------------------
@@ -80,13 +58,11 @@ function parseArgs() {
80
58
 
81
59
  for (let i = 0; i < args.length; i++) {
82
60
  if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) {
83
- result.address = args[i + 1];
84
- i++;
61
+ result.address = args[++i];
85
62
  } else if (args[i] === '--json' || args[i] === '--json-output') {
86
63
  result.json = true;
87
64
  } else if (args[i] === '--rpc' && args[i + 1]) {
88
- result.rpc = args[i + 1];
89
- i++;
65
+ result.rpc = args[++i];
90
66
  } else if (args[i] === '--help' || args[i] === '-h') {
91
67
  result.help = true;
92
68
  }
@@ -124,6 +100,11 @@ ${C.bright}OPTIONS${C.reset}
124
100
  --rpc <url> RPC endpoint (default: AETHER_RPC or localhost:8899)
125
101
  --help Show this help
126
102
 
103
+ ${C.bright}SDK METHODS USED${C.reset}
104
+ client.getSlot() → GET /v1/slot
105
+ client.getStakePositions() → GET /v1/stake/<address>
106
+ client.getAccountInfo() → GET /v1/account/<addr>
107
+
127
108
  ${C.bright}EXAMPLES${C.reset}
128
109
  aether stake-positions --address ATH3abc...
129
110
  aether stake-positions --address ATH3abc... --json
@@ -138,6 +119,7 @@ ${C.bright}EXAMPLES${C.reset}
138
119
  }
139
120
 
140
121
  const rpcUrl = opts.rpc || getDefaultRpc();
122
+ const client = createClient(rpcUrl);
141
123
  const address = opts.address;
142
124
  const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
143
125
 
@@ -148,20 +130,17 @@ ${C.bright}EXAMPLES${C.reset}
148
130
  }
149
131
 
150
132
  try {
151
- // Fetch stake accounts
152
- const res = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(rawAddr)}`);
153
-
154
- let stakeAccounts = [];
155
- if (Array.isArray(res)) {
156
- stakeAccounts = res;
157
- } else if (res && typeof res === 'object') {
158
- stakeAccounts = res.accounts || res.stake_accounts || res.data || [];
159
- }
133
+ // Verify chain connectivity via SDK (real RPC call)
134
+ const slot = await client.getSlot().catch(() => null);
135
+
136
+ // Fetch stake positions via SDK (real RPC call to GET /v1/stake/<address>)
137
+ const stakeAccounts = await client.getStakePositions(rawAddr);
160
138
 
161
139
  if (opts.json) {
162
140
  const totalLamports = stakeAccounts.reduce((sum, acc) => sum + (acc.stake_lamports || acc.lamports || 0), 0);
163
141
  console.log(JSON.stringify({
164
142
  wallet_address: address,
143
+ slot,
165
144
  stake_accounts: stakeAccounts.map(acc => ({
166
145
  stake_account: acc.pubkey || acc.publicKey || acc.account || 'unknown',
167
146
  validator: acc.validator || acc.delegate || acc.validator_address || 'unknown',
@@ -173,6 +152,9 @@ ${C.bright}EXAMPLES${C.reset}
173
152
  total_staked_lamports: totalLamports,
174
153
  total_staked_aeth: (totalLamports / 1e9).toFixed(4),
175
154
  count: stakeAccounts.length,
155
+ rpc: rpcUrl,
156
+ cli_version: CLI_VERSION,
157
+ fetched_at: new Date().toISOString(),
176
158
  }, null, 2));
177
159
  return;
178
160
  }
@@ -213,8 +195,11 @@ ${C.bright}EXAMPLES${C.reset}
213
195
 
214
196
  } catch (err) {
215
197
  console.log(` ${C.red}? Failed to fetch stake positions:${C.reset} ${err.message}\n`);
198
+ console.log(` ${C.dim} Set custom RPC: AETHER_RPC=https://your-rpc-url${C.reset}\n`);
216
199
  process.exit(1);
217
200
  }
218
201
  }
219
202
 
220
203
  stakePositionsCommand();
204
+
205
+ module.exports = { stakePositionsCommand };