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
package/commands/supply.js
CHANGED
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
* Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
const
|
|
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
|
-
//
|
|
38
|
+
// SDK Import - Real blockchain RPC calls via @jellylegsai/aether-sdk
|
|
40
39
|
// ---------------------------------------------------------------------------
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
41
|
+
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
42
|
+
const aether = require(sdkPath);
|
|
45
43
|
|
|
46
|
-
function
|
|
47
|
-
return
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
*
|
|
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:
|
|
123
|
-
const res = await
|
|
124
|
-
if (res &&
|
|
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
|
|
137
|
-
if (epochInfo
|
|
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
|
-
//
|
|
167
|
-
const
|
|
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
|
|
188
|
-
if (epochInfo &&
|
|
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
|
-
*
|
|
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
|
-
|
|
213
|
-
|
|
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 */ }
|
|
@@ -222,10 +174,12 @@ async function fetchBurnedSupply(rpc) {
|
|
|
222
174
|
/**
|
|
223
175
|
* Fetch circulating supply = total - non-circulating (locked/vesting/burned).
|
|
224
176
|
* Non-circulating includes: burn address, escrow/staking vault, team vesting.
|
|
177
|
+
* Uses SDK client for RPC calls.
|
|
225
178
|
*/
|
|
226
179
|
async function fetchNonCirculatingAccounts(rpc) {
|
|
180
|
+
const client = createClient(rpc);
|
|
227
181
|
try {
|
|
228
|
-
const res = await
|
|
182
|
+
const res = await client._httpGet('/v1/supply/non-circulating');
|
|
229
183
|
if (res && !res.error && Array.isArray(res.accounts)) {
|
|
230
184
|
let total = BigInt(0);
|
|
231
185
|
for (const acct of res.accounts) {
|
package/commands/tps.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* aether-cli tps
|
|
4
|
+
*
|
|
5
|
+
* Monitor real-time transactions per second (TPS) on the Aether blockchain.
|
|
6
|
+
* Uses @jellylegsai/aether-sdk for real RPC calls to /v1/tps endpoint.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* aether tps Show current TPS
|
|
10
|
+
* aether tps --monitor Continuous monitoring (updates every 2s)
|
|
11
|
+
* aether tps --interval <sec> Custom interval for monitoring (default: 2)
|
|
12
|
+
* aether tps --json JSON output for scripting
|
|
13
|
+
* aether tps --rpc <url> Custom RPC endpoint
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* aether tps # Single TPS reading
|
|
17
|
+
* aether tps --monitor # Live monitoring dashboard
|
|
18
|
+
* aether tps --monitor --interval 1 # Update every second
|
|
19
|
+
* aether tps --json # JSON for alerting/monitoring
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
24
|
+
const aether = require(sdkPath);
|
|
25
|
+
|
|
26
|
+
// ANSI colours
|
|
27
|
+
const C = {
|
|
28
|
+
reset: '\x1b[0m',
|
|
29
|
+
bright: '\x1b[1m',
|
|
30
|
+
dim: '\x1b[2m',
|
|
31
|
+
red: '\x1b[31m',
|
|
32
|
+
green: '\x1b[32m',
|
|
33
|
+
yellow: '\x1b[33m',
|
|
34
|
+
cyan: '\x1b[36m',
|
|
35
|
+
magenta: '\x1b[35m',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const CLI_VERSION = '1.0.0';
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Helpers
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
function getDefaultRpc() {
|
|
45
|
+
return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function createClient(rpc) {
|
|
49
|
+
return new aether.AetherClient({ rpcUrl: rpc });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function tpsColor(tps) {
|
|
53
|
+
if (tps === null || tps === undefined) return C.red;
|
|
54
|
+
if (tps >= 1000) return C.green;
|
|
55
|
+
if (tps >= 100) return C.cyan;
|
|
56
|
+
if (tps >= 10) return C.yellow;
|
|
57
|
+
return C.red;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function tpsLabel(tps) {
|
|
61
|
+
if (tps === null || tps === undefined) return '✗ unreachable';
|
|
62
|
+
if (tps >= 1000) return `● ${tps.toLocaleString()} TPS (excellent)`;
|
|
63
|
+
if (tps >= 100) return `● ${tps.toLocaleString()} TPS (good)`;
|
|
64
|
+
if (tps >= 10) return `○ ${tps.toLocaleString()} TPS (fair)`;
|
|
65
|
+
return `○ ${tps.toLocaleString()} TPS (low)`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Single TPS reading
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
async function getTpsOnce(rpcUrl) {
|
|
73
|
+
const client = createClient(rpcUrl);
|
|
74
|
+
const start = Date.now();
|
|
75
|
+
let tps = null;
|
|
76
|
+
let error = null;
|
|
77
|
+
let latencyMs = null;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// Real RPC call: GET /v1/tps
|
|
81
|
+
tps = await client.getTPS();
|
|
82
|
+
latencyMs = Date.now() - start;
|
|
83
|
+
} catch (err) {
|
|
84
|
+
latencyMs = Date.now() - start;
|
|
85
|
+
error = err.message;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return { tps, error, latencyMs, rpcUrl, timestamp: new Date() };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Continuous monitoring
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
async function monitorTps(rpcUrl, intervalSec) {
|
|
96
|
+
console.log(`\n${C.bright}${C.cyan}── Aether TPS Monitor ───────────────────────────────────${C.reset}`);
|
|
97
|
+
console.log(` ${C.dim}RPC: ${rpcUrl}${C.reset}`);
|
|
98
|
+
console.log(` ${C.dim}Interval: ${intervalSec}s${C.reset}`);
|
|
99
|
+
console.log(` ${C.dim}Press Ctrl+C to stop${C.reset}\n`);
|
|
100
|
+
|
|
101
|
+
const history = [];
|
|
102
|
+
const maxHistory = 20;
|
|
103
|
+
|
|
104
|
+
process.on('SIGINT', () => {
|
|
105
|
+
console.log(`\n${C.dim}Monitoring stopped.${C.reset}`);
|
|
106
|
+
if (history.length > 1) {
|
|
107
|
+
const tpsValues = history.map(h => h.tps).filter(t => t !== null);
|
|
108
|
+
if (tpsValues.length > 0) {
|
|
109
|
+
const avg = Math.round(tpsValues.reduce((a, b) => a + b, 0) / tpsValues.length);
|
|
110
|
+
const min = Math.min(...tpsValues);
|
|
111
|
+
const max = Math.max(...tpsValues);
|
|
112
|
+
console.log(` ${C.bright}Summary:${C.reset} avg=${avg} min=${min} max=${max} samples=${history.length}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
console.log();
|
|
116
|
+
process.exit(0);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
while (true) {
|
|
120
|
+
const result = await getTpsOnce(rpcUrl);
|
|
121
|
+
history.push(result);
|
|
122
|
+
if (history.length > maxHistory) history.shift();
|
|
123
|
+
|
|
124
|
+
// Clear line and print
|
|
125
|
+
process.stdout.write('\x1b[2K\r');
|
|
126
|
+
|
|
127
|
+
const tc = tpsColor(result.tps);
|
|
128
|
+
const barLen = result.tps !== null ? Math.min(30, Math.floor(result.tps / 50)) : 0;
|
|
129
|
+
const bar = tc + '█'.repeat(barLen) + C.dim + '░'.repeat(30 - barLen) + C.reset;
|
|
130
|
+
|
|
131
|
+
const slotInfo = result.tps !== null ? ` ${C.dim}RPC latency: ${result.latencyMs}ms${C.reset}` : '';
|
|
132
|
+
|
|
133
|
+
console.log(` ${tc}${bar}${C.reset} ${tpsLabel(result.tps)}${C.reset}${slotInfo}`);
|
|
134
|
+
|
|
135
|
+
// Show trend
|
|
136
|
+
if (history.length >= 3) {
|
|
137
|
+
const recent = history.slice(-3).map(h => h.tps).filter(t => t !== null);
|
|
138
|
+
if (recent.length >= 2) {
|
|
139
|
+
const trend = recent[recent.length - 1] - recent[0];
|
|
140
|
+
const arrow = trend > 0 ? C.green + '▲' : trend < 0 ? C.red + '▼' : C.dim + '─';
|
|
141
|
+
console.log(` ${C.dim}Trend: ${arrow} ${Math.abs(trend)} TPS${C.reset}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await new Promise(resolve => setTimeout(resolve, intervalSec * 1000));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Main command
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
async function tpsCommand() {
|
|
154
|
+
const args = process.argv.slice(2);
|
|
155
|
+
const asJson = args.includes('--json') || args.includes('-j');
|
|
156
|
+
const isMonitor = args.includes('--monitor') || args.includes('-m');
|
|
157
|
+
const rpcIdx = args.findIndex(a => a === '--rpc' || a === '-r');
|
|
158
|
+
const rpcUrl = rpcIdx !== -1 && args[rpcIdx + 1] ? args[rpcIdx + 1] : getDefaultRpc();
|
|
159
|
+
|
|
160
|
+
const intervalIdx = args.findIndex(a => a === '--interval' || a === '-i');
|
|
161
|
+
const intervalSec = intervalIdx !== -1 && args[intervalIdx + 1]
|
|
162
|
+
? Math.max(1, parseInt(args[intervalIdx + 1], 10) || 2)
|
|
163
|
+
: 2;
|
|
164
|
+
|
|
165
|
+
if (isMonitor) {
|
|
166
|
+
await monitorTps(rpcUrl, intervalSec);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Single reading
|
|
171
|
+
const result = await getTpsOnce(rpcUrl);
|
|
172
|
+
|
|
173
|
+
if (asJson) {
|
|
174
|
+
console.log(JSON.stringify({
|
|
175
|
+
rpc: rpcUrl,
|
|
176
|
+
tps: result.tps,
|
|
177
|
+
online: result.tps !== null,
|
|
178
|
+
latency_ms: result.latencyMs,
|
|
179
|
+
error: result.error || null,
|
|
180
|
+
timestamp: result.timestamp.toISOString(),
|
|
181
|
+
cli_version: CLI_VERSION,
|
|
182
|
+
}, null, 2));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log(`\n${C.bright}${C.cyan}── Aether Network TPS ─────────────────────────────────${C.reset}\n`);
|
|
187
|
+
|
|
188
|
+
const tc = tpsColor(result.tps);
|
|
189
|
+
const barLen = result.tps !== null ? Math.min(40, Math.floor(result.tps / 50)) : 0;
|
|
190
|
+
const bar = tc + '█'.repeat(barLen) + C.dim + '░'.repeat(40 - barLen) + C.reset;
|
|
191
|
+
|
|
192
|
+
console.log(` ${C.dim}RPC:${C.reset} ${rpcUrl}`);
|
|
193
|
+
console.log(` ${C.dim}Latency:${C.reset} ${result.latencyMs}ms`);
|
|
194
|
+
console.log();
|
|
195
|
+
console.log(` ${C.bright}${tc}${tpsLabel(result.tps)}${C.reset}`);
|
|
196
|
+
console.log();
|
|
197
|
+
console.log(` ${bar}`);
|
|
198
|
+
console.log();
|
|
199
|
+
|
|
200
|
+
if (result.error) {
|
|
201
|
+
console.log(` ${C.red}✗ ${result.error}${C.reset}`);
|
|
202
|
+
console.log();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Context info
|
|
206
|
+
if (result.tps !== null) {
|
|
207
|
+
console.log(` ${C.dim}Network Health:${C.reset}`);
|
|
208
|
+
if (result.tps >= 1000) {
|
|
209
|
+
console.log(` ${C.green}● Network is handling high throughput${C.reset}`);
|
|
210
|
+
} else if (result.tps >= 100) {
|
|
211
|
+
console.log(` ${C.cyan}● Network operating normally${C.reset}`);
|
|
212
|
+
} else if (result.tps >= 10) {
|
|
213
|
+
console.log(` ${C.yellow}○ Network has low activity${C.reset}`);
|
|
214
|
+
} else {
|
|
215
|
+
console.log(` ${C.red}○ Network is idle or experiencing issues${C.reset}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log();
|
|
220
|
+
console.log(` ${C.dim}Run ${C.cyan}aether tps --monitor${C.reset}${C.dim} for live tracking.${C.reset}\n`);
|
|
221
|
+
|
|
222
|
+
if (result.tps === null) {
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Entry point
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
module.exports = { tpsCommand };
|
|
232
|
+
|
|
233
|
+
if (require.main === module) {
|
|
234
|
+
tpsCommand().catch(err => {
|
|
235
|
+
console.error(`\n${C.red}TPS command failed:${C.reset} ${err.message}\n`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
});
|
|
238
|
+
}
|