aether-hub 1.2.5 → 1.2.7

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 };
@@ -15,9 +15,8 @@
15
15
  * Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
16
16
  */
17
17
 
18
- const http = require('http');
19
- const https = require('https');
20
18
  const os = require('os');
19
+ const path = require('path');
21
20
 
22
21
  // ANSI colours
23
22
  const C = {
@@ -33,66 +32,20 @@ const C = {
33
32
 
34
33
  const CLI_VERSION = '1.0.0';
35
34
 
35
+ // Import SDK for real blockchain RPC calls
36
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
37
+ const aether = require(sdkPath);
38
+
36
39
  // ---------------------------------------------------------------------------
37
40
  // Helpers
38
41
  // ---------------------------------------------------------------------------
39
42
 
40
43
  function getDefaultRpc() {
41
- return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
42
- }
43
-
44
- function httpRequest(rpcUrl, pathStr, timeoutMs = 10000) {
45
- return new Promise((resolve, reject) => {
46
- const url = new URL(pathStr, rpcUrl);
47
- const lib = url.protocol === 'https:' ? https : http;
48
- const req = lib.request({
49
- hostname: url.hostname,
50
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
51
- path: url.pathname + url.search,
52
- method: 'GET',
53
- timeout: timeoutMs,
54
- headers: { 'Content-Type': 'application/json' },
55
- }, (res) => {
56
- let data = '';
57
- res.on('data', (chunk) => data += chunk);
58
- res.on('end', () => {
59
- try { resolve(JSON.parse(data)); }
60
- catch { resolve({ raw: data }); }
61
- });
62
- });
63
- req.on('error', reject);
64
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout after ' + timeoutMs + 'ms')); });
65
- req.end();
66
- });
44
+ return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
67
45
  }
68
46
 
69
- function httpPost(rpcUrl, pathStr, body, timeoutMs = 10000) {
70
- return new Promise((resolve, reject) => {
71
- const url = new URL(pathStr, rpcUrl);
72
- const lib = url.protocol === 'https:' ? https : http;
73
- const bodyStr = JSON.stringify(body);
74
- const req = lib.request({
75
- hostname: url.hostname,
76
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
77
- path: url.pathname + url.search,
78
- method: 'POST',
79
- timeout: timeoutMs,
80
- headers: {
81
- 'Content-Type': 'application/json',
82
- 'Content-Length': Buffer.byteLength(bodyStr),
83
- },
84
- }, (res) => {
85
- let data = '';
86
- res.on('data', (chunk) => data += chunk);
87
- res.on('end', () => {
88
- try { resolve(JSON.parse(data)); }
89
- catch { resolve(data); }
90
- });
91
- });
92
- req.on('error', reject);
93
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout after ' + timeoutMs + 'ms')); });
94
- req.end();
95
- });
47
+ function createClient(rpc) {
48
+ return new aether.AetherClient({ rpcUrl: rpc });
96
49
  }
97
50
 
98
51
  function formatAether(lamports) {
@@ -124,7 +77,7 @@ function loadIdentity() {
124
77
  // ---------------------------------------------------------------------------
125
78
 
126
79
  async function statusCommand() {
127
- const args = process.argv.slice(3); // skip "aether status"
80
+ const args = process.argv.slice(2); // [node, status.js, ...]
128
81
  const isJson = args.includes('--json') || args.includes('-j');
129
82
  const isCompact = args.includes('--compact');
130
83
  const includeValidator = args.includes('--validator');
@@ -168,130 +121,133 @@ async function statusCommand() {
168
121
  return;
169
122
  }
170
123
 
171
- printDashboard(data, errors, includeValidator);
124
+ printDashboard(data, errors, includeValidator, rpc);
172
125
  }
173
126
 
174
127
  async function fetchEpochInfo(rpc) {
175
- const [epochResp, slotResp] = await Promise.all([
176
- httpPost(rpc, '/v1/epoch/info', { jsonrpc: '2.0', id: 1, method: 'getEpochInfo' }),
177
- httpPost(rpc, '/v1Slot', { jsonrpc: '2.0', id: 1, method: 'getSlot' }),
178
- ]);
179
-
180
- const epoch = epochResp?.result || {};
181
- const currentSlot = slotResp?.result || epoch.currentSlot || 0;
182
- const slotsInEpoch = epoch.slotsInEpoch || 432000;
183
- const slotIndex = currentSlot % slotsInEpoch;
184
- const epochProgress = slotsInEpoch > 0 ? (slotIndex / slotsInEpoch * 100).toFixed(1) : '0';
185
-
186
- // Estimate time remaining (assuming 400ms slots)
187
- const slotsRemaining = slotsInEpoch - slotIndex;
188
- const secsRemaining = Math.round(slotsRemaining * 0.4);
189
- const minsRemaining = Math.round(secsRemaining / 60);
190
- const timeStr = minsRemaining >= 60
191
- ? `${Math.floor(minsRemaining / 60)}h ${minsRemaining % 60}m`
192
- : `${minsRemaining}m`;
193
-
194
- return {
195
- epoch: epoch.epoch || 0,
196
- absoluteSlot: currentSlot,
197
- slotIndex,
198
- slotsInEpoch,
199
- progress: epochProgress,
200
- timeRemaining: timeStr,
201
- totalSlots: epoch.totalSlots || 0,
202
- };
128
+ const client = createClient(rpc);
129
+ try {
130
+ const epoch = await client.getEpochInfo();
131
+ const currentSlot = epoch.absoluteSlot || epoch.slot || 0;
132
+ const slotsInEpoch = epoch.slotsInEpoch || 432000;
133
+ const slotIndex = epoch.slotIndex || (currentSlot % slotsInEpoch);
134
+ const epochProgress = slotsInEpoch > 0 ? (slotIndex / slotsInEpoch * 100).toFixed(1) : '0';
135
+
136
+ // Estimate time remaining (assuming 400ms slots)
137
+ const slotsRemaining = slotsInEpoch - slotIndex;
138
+ const secsRemaining = Math.round(slotsRemaining * 0.4);
139
+ const minsRemaining = Math.round(secsRemaining / 60);
140
+ const timeStr = minsRemaining >= 60
141
+ ? `${Math.floor(minsRemaining / 60)}h ${minsRemaining % 60}m`
142
+ : `${minsRemaining}m`;
143
+
144
+ return {
145
+ epoch: epoch.epoch || 0,
146
+ absoluteSlot: currentSlot,
147
+ slotIndex,
148
+ slotsInEpoch,
149
+ progress: epochProgress,
150
+ timeRemaining: timeStr,
151
+ totalSlots: epoch.totalSlots || 0,
152
+ };
153
+ } catch (e) {
154
+ throw new Error('Epoch info fetch failed: ' + e.message);
155
+ }
203
156
  }
204
157
 
205
158
  async function fetchSupplyInfo(rpc) {
206
- const resp = await httpPost(rpc, '/v1/supply', { jsonrpc: '2.0', id: 1, method: 'getSupply' });
207
- const supply = resp?.result?.value || {};
208
- const total = BigInt(supply.total || 0);
209
- const circulating = BigInt(supply.circulating || 0);
210
- const nonCirculating = BigInt(supply.nonCirculating || 0);
211
-
212
- return {
213
- total: total.toString(),
214
- totalFormatted: formatAether(total.toString()),
215
- circulating: circulating.toString(),
216
- circulatingFormatted: formatAether(circulating.toString()),
217
- nonCirculating: nonCirculating.toString(),
218
- nonCirculatingFormatted: formatAether(nonCirculating.toString()),
219
- };
159
+ const client = createClient(rpc);
160
+ try {
161
+ const supply = await client.getSupply();
162
+ const total = BigInt(supply.total || 0);
163
+ const circulating = BigInt(supply.circulating || 0);
164
+ const nonCirculating = BigInt(supply.nonCirculating || 0);
165
+
166
+ return {
167
+ total: total.toString(),
168
+ totalFormatted: formatAether(total.toString()),
169
+ circulating: circulating.toString(),
170
+ circulatingFormatted: formatAether(circulating.toString()),
171
+ nonCirculating: nonCirculating.toString(),
172
+ nonCirculatingFormatted: formatAether(nonCirculating.toString()),
173
+ };
174
+ } catch (e) {
175
+ throw new Error('Supply info fetch failed: ' + e.message);
176
+ }
220
177
  }
221
178
 
222
179
  async function fetchNetworkInfo(rpc) {
223
- const [slotResp, blockResp, peersResp] = await Promise.all([
224
- httpPost(rpc, '/v1Slot', { jsonrpc: '2.0', id: 1, method: 'getSlot' }),
225
- httpPost(rpc, '/v1Block', { jsonrpc: '2.0', id: 1, method: 'getBlockTime', params: [0] }),
226
- httpPost(rpc, '/v1Peers', { jsonrpc: '2.0', id: 1, method: 'getClusterPeers' }),
227
- ]);
228
-
229
- const blockHeight = slotResp?.result || 0;
230
- const blockTime = blockResp?.result || null;
231
- const peers = Array.isArray(peersResp?.result) ? peersResp.result : [];
232
-
233
- return {
234
- blockHeight,
235
- blockTime,
236
- peerCount: peers.length,
237
- peers: peers.slice(0, 5), // first 5 for detail
238
- };
180
+ const client = createClient(rpc);
181
+ try {
182
+ const [slot, blockHeight, peers] = await Promise.all([
183
+ client.getSlot(),
184
+ client.getBlockHeight(),
185
+ client.getClusterPeers(),
186
+ ]);
187
+
188
+ return {
189
+ blockHeight: blockHeight || slot || 0,
190
+ blockTime: null,
191
+ peerCount: Array.isArray(peers) ? peers.length : 0,
192
+ peers: (Array.isArray(peers) ? peers : []).slice(0, 5),
193
+ };
194
+ } catch (e) {
195
+ throw new Error('Network info fetch failed: ' + e.message);
196
+ }
239
197
  }
240
198
 
241
199
  async function fetchVersionInfo(rpc) {
200
+ const client = createClient(rpc);
242
201
  try {
243
- const resp = await httpPost(rpc, '/v1Version', { jsonrpc: '2.0', id: 1, method: 'getVersion' });
244
- return resp?.result || {};
202
+ return await client.getVersion();
245
203
  } catch {
246
204
  return {};
247
205
  }
248
206
  }
249
207
 
250
208
  async function fetchRewardsSummary(rpc, address) {
251
- // Fetch stake accounts for wallet, then fetch rewards for each
252
- const allAccountsResp = await httpPost(rpc, '/v1Stake/accounts', {
253
- jsonrpc: '2.0', id: 1, method: 'getStakeAccounts', params: [address],
254
- }).catch(() => null);
255
-
256
- const stakeAccounts = (allAccountsResp?.result?.value || [])
257
- .filter(a => a.owner && (!Array.isArray(a.owner) || a.owner.length > 0))
258
- .map(a => a.pubkey || a);
259
-
260
- if (stakeAccounts.length === 0) return null;
261
-
262
- const rewardsResults = await Promise.all(
263
- stakeAccounts.slice(0, 10).map(async (sa) => {
264
- try {
265
- const resp = await httpPost(rpc, '/v1Stake/rewards', {
266
- jsonrpc: '2.0', id: 1, method: 'getStakeRewards', params: [sa],
267
- });
268
- const rewards = resp?.result?.rewards || [];
269
- let total = BigInt(0);
270
- for (const r of rewards) {
271
- total += BigInt(r.estimatedReward || 0);
209
+ const client = createClient(rpc);
210
+ try {
211
+ // Get stake positions for the address (real RPC call via SDK)
212
+ const stakePositions = await client.getStakePositions(address);
213
+
214
+ if (!stakePositions || stakePositions.length === 0) return null;
215
+
216
+ const rewardsResults = await Promise.all(
217
+ stakePositions.slice(0, 10).map(async (stake) => {
218
+ try {
219
+ const stakeAccount = stake.stakeAccount || stake.account || stake.pubkey || stake;
220
+ const rewards = await client.getRewards(stakeAccount);
221
+ const total = BigInt(rewards.total || rewards.amount || 0);
222
+ return {
223
+ stakeAccount,
224
+ estimatedRewards: total.toString(),
225
+ estimatedRewardsFormatted: formatAether(total.toString())
226
+ };
227
+ } catch {
228
+ return { stakeAccount: stake.stakeAccount || stake, estimatedRewards: '0', estimatedRewardsFormatted: '0 AETH' };
272
229
  }
273
- return { stakeAccount: sa, estimatedRewards: total.toString(), estimatedRewardsFormatted: formatAether(total.toString()) };
274
- } catch {
275
- return { stakeAccount: sa, estimatedRewards: '0', estimatedRewardsFormatted: '0 AETH' };
276
- }
277
- })
278
- );
279
-
280
- let totalRewards = BigInt(0);
281
- for (const r of rewardsResults) {
282
- totalRewards += BigInt(r.estimatedRewards);
283
- }
230
+ })
231
+ );
232
+
233
+ let totalRewards = BigInt(0);
234
+ for (const r of rewardsResults) {
235
+ totalRewards += BigInt(r.estimatedRewards);
236
+ }
284
237
 
285
- return {
286
- address,
287
- totalRewards: totalRewards.toString(),
288
- totalRewardsFormatted: formatAether(totalRewards.toString()),
289
- activeAccounts: rewardsResults.filter(r => BigInt(r.estimatedRewards) > 0n).length,
290
- totalAccounts: rewardsResults.length,
291
- };
238
+ return {
239
+ address,
240
+ totalRewards: totalRewards.toString(),
241
+ totalRewardsFormatted: formatAether(totalRewards.toString()),
242
+ activeAccounts: rewardsResults.filter(r => BigInt(r.estimatedRewards) > 0n).length,
243
+ totalAccounts: rewardsResults.length,
244
+ };
245
+ } catch (e) {
246
+ throw new Error('Rewards fetch failed: ' + e.message);
247
+ }
292
248
  }
293
249
 
294
- function printDashboard(data, errors, includeValidator) {
250
+ function printDashboard(data, errors, includeValidator, rpc) {
295
251
  const { epoch, supply, network, version, validator, rewards, defaultWallet } = data;
296
252
 
297
253
  console.log(`\n${C.bright}${C.cyan} ╔══════════════════════════════════════════════════════════╗${C.reset}`);
@@ -17,8 +17,7 @@
17
17
  * Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
18
18
  */
19
19
 
20
- const http = require('http');
21
- const https = require('https');
20
+ const path = require('path');
22
21
 
23
22
  // ANSI colours
24
23
  const C = {
@@ -36,63 +35,19 @@ const C = {
36
35
  const CLI_VERSION = '1.0.0';
37
36
 
38
37
  // ---------------------------------------------------------------------------
39
- // Helpers
38
+ // SDK Import - Real blockchain RPC calls via @jellylegsai/aether-sdk
40
39
  // ---------------------------------------------------------------------------
41
40
 
42
- function getDefaultRpc() {
43
- return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
44
- }
41
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
42
+ const aether = require(sdkPath);
45
43
 
46
- function httpRequest(rpcUrl, pathStr, timeoutMs = 10000) {
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
- timeout: timeoutMs,
56
- headers: { 'Content-Type': 'application/json' },
57
- }, (res) => {
58
- let data = '';
59
- res.on('data', (chunk) => data += chunk);
60
- res.on('end', () => {
61
- try { resolve(JSON.parse(data)); }
62
- catch { resolve({ raw: data }); }
63
- });
64
- });
65
- req.on('error', reject);
66
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout after ' + timeoutMs + 'ms')); });
67
- req.end();
68
- });
44
+ function getDefaultRpc() {
45
+ return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
69
46
  }
70
47
 
71
- function httpPost(rpcUrl, pathStr, body, timeoutMs = 10000) {
72
- return new Promise((resolve, reject) => {
73
- const url = new URL(pathStr, rpcUrl);
74
- const lib = url.protocol === 'https:' ? https : http;
75
- const bodyStr = JSON.stringify(body);
76
- const req = lib.request({
77
- hostname: url.hostname,
78
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
79
- path: url.pathname + url.search,
80
- method: 'POST',
81
- timeout: timeoutMs,
82
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(bodyStr) },
83
- }, (res) => {
84
- let data = '';
85
- res.on('data', (chunk) => data += chunk);
86
- res.on('end', () => {
87
- try { resolve(JSON.parse(data)); }
88
- catch { resolve({ raw: data }); }
89
- });
90
- });
91
- req.on('error', reject);
92
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout after ' + timeoutMs + 'ms')); });
93
- req.write(bodyStr);
94
- req.end();
95
- });
48
+ /** Create SDK client */
49
+ function createClient(rpcUrl) {
50
+ return new aether.AetherClient({ rpcUrl });
96
51
  }
97
52
 
98
53
  function formatAether(lamports) {
@@ -110,22 +65,23 @@ function formatLargeNum(n) {
110
65
  }
111
66
 
112
67
  // ---------------------------------------------------------------------------
113
- // Core supply fetchers
68
+ // Core supply fetchers using SDK
114
69
  // ---------------------------------------------------------------------------
115
70
 
116
71
  /**
117
- * Fetch the total supply of AETH from the chain.
118
- * Uses the supply inflation schedule / mint account.
72
+ * Fetch the total supply of AETH from the chain using SDK.
73
+ * Makes real RPC call: GET /v1/supply
119
74
  */
120
75
  async function fetchTotalSupply(rpc) {
76
+ const client = createClient(rpc);
121
77
  try {
122
- // Primary: dedicated supply endpoint
123
- const res = await httpRequest(rpc, '/v1/supply');
124
- if (res && !res.error && (res.total !== undefined || res.supply !== undefined)) {
78
+ // Primary: SDK getSupply() → GET /v1/supply
79
+ const res = await client.getSupply();
80
+ if (res && (res.total !== undefined || res.supply !== undefined)) {
125
81
  return {
126
82
  total: BigInt(res.total || res.supply?.total || 0),
127
83
  circulating: BigInt(res.circulating || res.supply?.circulating || 0),
128
- nonCirculating: BigInt(res.non_circulating || res.supply?.non_circulating || 0),
84
+ nonCirculating: BigInt(res.non_circulating || res.nonCirculating || res.supply?.non_circulating || 0),
129
85
  source: 'rpc_v1_supply',
130
86
  };
131
87
  }
@@ -133,8 +89,8 @@ async function fetchTotalSupply(rpc) {
133
89
 
134
90
  // Fallback: fetch epoch info which contains total token count
135
91
  try {
136
- const epochInfo = await httpRequest(rpc, '/v1/epoch-info');
137
- if (epochInfo && !epochInfo.error) {
92
+ const epochInfo = await client.getEpochInfo();
93
+ if (epochInfo) {
138
94
  const totalStaked = BigInt(epochInfo.total_staked || 0);
139
95
  const rewardsPerEpoch = BigInt(epochInfo.rewards_per_epoch || '2000000000');
140
96
  const currentEpoch = BigInt(epochInfo.epoch || 0);
@@ -159,33 +115,27 @@ async function fetchTotalSupply(rpc) {
159
115
  }
160
116
 
161
117
  /**
162
- * Fetch staked supply by querying stake program accounts.
118
+ * Fetch staked supply by querying stake program accounts using SDK.
119
+ * Makes real RPC call: GET /v1/validators
163
120
  */
164
121
  async function fetchStakedSupply(rpc) {
122
+ const client = createClient(rpc);
165
123
  try {
166
- // Try stake program accounts count / total
167
- const res = await httpRequest(rpc, '/v1/stake/total');
168
- if (res && !res.error && res.total_staked !== undefined) {
169
- return BigInt(res.total_staked);
170
- }
171
- } catch { /* fall through */ }
172
-
173
- try {
174
- // Fallback: sum delegated stake across top validators
175
- const validators = await httpRequest(rpc, '/v1/validators?limit=50');
124
+ // SDK getValidators() GET /v1/validators
125
+ const validators = await client.getValidators();
176
126
  if (validators && Array.isArray(validators)) {
177
127
  let total = BigInt(0);
178
128
  for (const v of validators) {
179
- total += BigInt(v.delegated_stake || v.stake || 0);
129
+ total += BigInt(v.delegated_stake || v.stake || v.delegatedStake || 0);
180
130
  }
181
131
  return total;
182
132
  }
183
133
  } catch { /* fall through */ }
184
134
 
185
135
  try {
186
- // Last resort: epoch info staked amount
187
- const epochInfo = await httpRequest(rpc, '/v1/epoch-info');
188
- if (epochInfo && !epochInfo.error && epochInfo.total_staked) {
136
+ // Last resort: epoch info staked amount via SDK
137
+ const epochInfo = await client.getEpochInfo();
138
+ if (epochInfo && epochInfo.total_staked) {
189
139
  return BigInt(epochInfo.total_staked);
190
140
  }
191
141
  } catch { /* fall through */ }
@@ -194,10 +144,11 @@ async function fetchStakedSupply(rpc) {
194
144
  }
195
145
 
196
146
  /**
197
- * Estimate burned supply by querying accounts at known burn/mint addresses.
198
- * Uses a set of common Aether burn addresses.
147
+ * Estimate burned supply by querying accounts at known burn/mint addresses using SDK.
148
+ * Makes real RPC calls: GET /v1/account/<address>
199
149
  */
200
150
  async function fetchBurnedSupply(rpc) {
151
+ const client = createClient(rpc);
201
152
  const BURN_ADDRESSES = [
202
153
  'ATH1111111111111111111111111111111111111', // mint authority burn
203
154
  'ATH2222222222222222222222222222222222222', // zero authority
@@ -209,8 +160,9 @@ async function fetchBurnedSupply(rpc) {
209
160
  for (const addr of BURN_ADDRESSES) {
210
161
  try {
211
162
  const rawAddr = addr.startsWith('ATH') ? addr.slice(3) : addr;
212
- const account = await httpRequest(rpc, `/v1/account/${encodeURIComponent(rawAddr)}`);
213
- if (account && !account.error && account.lamports !== undefined && Number(account.lamports) > 0) {
163
+ // SDK getAccountInfo() GET /v1/account/<address>
164
+ const account = await client.getAccountInfo(rawAddr);
165
+ if (account && account.lamports !== undefined && Number(account.lamports) > 0) {
214
166
  totalBurned += BigInt(account.lamports);
215
167
  }
216
168
  } catch { /* skip inaccessible addresses */ }