@jellylegsai/aether-cli 1.8.0

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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/aether-cli-1.0.0.tgz +0 -0
  4. package/aether-cli-1.8.0.tgz +0 -0
  5. package/aether-hub-1.0.5.tgz +0 -0
  6. package/aether-hub-1.1.8.tgz +0 -0
  7. package/aether-hub-1.2.1.tgz +0 -0
  8. package/commands/account.js +280 -0
  9. package/commands/apy.js +499 -0
  10. package/commands/balance.js +241 -0
  11. package/commands/blockhash.js +181 -0
  12. package/commands/broadcast.js +387 -0
  13. package/commands/claim.js +490 -0
  14. package/commands/config.js +851 -0
  15. package/commands/delegations.js +582 -0
  16. package/commands/doctor.js +769 -0
  17. package/commands/emergency.js +667 -0
  18. package/commands/epoch.js +275 -0
  19. package/commands/fees.js +276 -0
  20. package/commands/index.js +78 -0
  21. package/commands/info.js +495 -0
  22. package/commands/init.js +816 -0
  23. package/commands/install.js +666 -0
  24. package/commands/kyc.js +272 -0
  25. package/commands/logs.js +315 -0
  26. package/commands/monitor.js +431 -0
  27. package/commands/multisig.js +701 -0
  28. package/commands/network.js +429 -0
  29. package/commands/nft.js +857 -0
  30. package/commands/ping.js +266 -0
  31. package/commands/price.js +253 -0
  32. package/commands/rewards.js +931 -0
  33. package/commands/sdk-test.js +477 -0
  34. package/commands/sdk.js +656 -0
  35. package/commands/slot.js +155 -0
  36. package/commands/snapshot.js +470 -0
  37. package/commands/stake-info.js +139 -0
  38. package/commands/stake-positions.js +205 -0
  39. package/commands/stake.js +516 -0
  40. package/commands/stats.js +396 -0
  41. package/commands/status.js +327 -0
  42. package/commands/supply.js +391 -0
  43. package/commands/tps.js +238 -0
  44. package/commands/transfer.js +495 -0
  45. package/commands/tx-history.js +346 -0
  46. package/commands/unstake.js +597 -0
  47. package/commands/validator-info.js +657 -0
  48. package/commands/validator-register.js +593 -0
  49. package/commands/validator-start.js +323 -0
  50. package/commands/validator-status.js +227 -0
  51. package/commands/validators.js +626 -0
  52. package/commands/wallet.js +1570 -0
  53. package/index.js +593 -0
  54. package/lib/errors.js +398 -0
  55. package/package.json +76 -0
  56. package/sdk/README.md +210 -0
  57. package/sdk/index.js +1639 -0
  58. package/sdk/package.json +34 -0
  59. package/sdk/rpc.js +254 -0
  60. package/sdk/test.js +85 -0
  61. package/test/doctor.test.js +76 -0
  62. package/validator-identity.json +4 -0
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aether-cli balance
4
+ *
5
+ * Query account balance from the Aether blockchain — real HTTP RPC calls,
6
+ * real data. No stubs, no mocks.
7
+ *
8
+ * Usage:
9
+ * aether balance <address> Query balance for an address
10
+ * aether balance Query default wallet balance
11
+ * aether balance --json JSON output for scripting
12
+ * aether balance --rpc <url> Query a specific RPC endpoint
13
+ * aether balance --lamports Show balance in lamports (not AETH)
14
+ *
15
+ * Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
16
+ * SDK: @jellylegsai/aether-sdk — makes REAL HTTP RPC calls to the chain
17
+ */
18
+
19
+ const os = require('os');
20
+ const path = require('path');
21
+ const fs = require('fs');
22
+
23
+ // Import error handling utilities
24
+ const {
25
+ withErrorHandling,
26
+ displayError,
27
+ validateAddress,
28
+ createRpcCaller,
29
+ C
30
+ } = require('../lib/errors');
31
+
32
+ // Import SDK — REAL blockchain RPC calls to http://127.0.0.1:8899
33
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
34
+ const aether = require(sdkPath);
35
+
36
+ const CLI_VERSION = '1.5.0';
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Helpers
40
+ // ---------------------------------------------------------------------------
41
+
42
+ function getDefaultRpc() {
43
+ return process.env.AETHER_RPC || (aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899');
44
+ }
45
+
46
+ function createClient(rpc) {
47
+ return new aether.AetherClient({ rpcUrl: rpc });
48
+ }
49
+
50
+ function lamportsToAeth(lamports) {
51
+ return (Number(lamports) / 1e9).toFixed(6);
52
+ }
53
+
54
+ function loadConfig() {
55
+ const aetherDir = path.join(os.homedir(), '.aether');
56
+ const cfgPath = path.join(aetherDir, 'config.json');
57
+ if (!fs.existsSync(cfgPath)) return { defaultWallet: null };
58
+ try {
59
+ return JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
60
+ }
61
+ catch {
62
+ return { defaultWallet: null };
63
+ }
64
+ }
65
+
66
+ function shortenAddress(addr) {
67
+ if (!addr) return 'unknown';
68
+ if (addr.length <= 10) return addr;
69
+ return `${addr.substring(0, 6)}...${addr.substring(addr.length - 4)}`;
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Argument parsing
74
+ // ---------------------------------------------------------------------------
75
+
76
+ function parseArgs() {
77
+ const args = process.argv.slice(2);
78
+ const options = {
79
+ rpc: getDefaultRpc(),
80
+ address: null,
81
+ asJson: false,
82
+ showLamports: false,
83
+ };
84
+
85
+ for (let i = 0; i < args.length; i++) {
86
+ const arg = args[i];
87
+ if (arg === '--rpc' || arg === '-r') {
88
+ options.rpc = args[++i];
89
+ } else if (arg === '--json' || arg === '-j') {
90
+ options.asJson = true;
91
+ } else if (arg === '--lamports' || arg === '-l') {
92
+ options.showLamports = true;
93
+ } else if (arg === '--help' || arg === '-h') {
94
+ showHelp();
95
+ process.exit(0);
96
+ } else if (!arg.startsWith('-') && !options.address) {
97
+ options.address = arg;
98
+ }
99
+ }
100
+
101
+ return options;
102
+ }
103
+
104
+ function showHelp() {
105
+ console.log(`
106
+ ${C.bright}${C.cyan}aether-cli balance${C.reset} - Query account balance
107
+
108
+ ${C.bright}Usage:${C.reset}
109
+ aether balance [address] [options]
110
+
111
+ ${C.bright}Options:${C.reset}
112
+ -r, --rpc <url> RPC endpoint (default: ${getDefaultRpc()})
113
+ -j, --json Output as JSON
114
+ -l, --lamports Show balance in lamports instead of AETH
115
+ -h, --help Show this help message
116
+
117
+ ${C.bright}Examples:${C.reset}
118
+ aether balance 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZvJkVG6PkD
119
+ aether balance --json
120
+ aether balance --lamports 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZvJkVG6PkD
121
+ `.trim());
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Balance fetching with retry logic
126
+ // ---------------------------------------------------------------------------
127
+
128
+ async function fetchBalance(client, address, options) {
129
+ const { asJson, showLamports } = options;
130
+
131
+ // Validate address format
132
+ try {
133
+ validateAddress(address);
134
+ } catch (error) {
135
+ error.isValidationError = true;
136
+ throw error;
137
+ }
138
+
139
+ // Create RPC caller with retry logic
140
+ const getBalance = createRpcCaller(client.getBalance.bind(client), {
141
+ maxRetries: 3,
142
+ initialDelay: 500,
143
+ onRetry: (error, attempt, max) => {
144
+ if (!asJson) {
145
+ console.log(
146
+ `${C.yellow}⚠ Retrying balance fetch (attempt ${attempt}/${max})...${C.reset}`
147
+ );
148
+ }
149
+ },
150
+ });
151
+
152
+ // Fetch balance with retry
153
+ const lamports = await getBalance(address);
154
+
155
+ // Handle response
156
+ if (lamports === undefined || lamports === null) {
157
+ throw new Error('Received invalid response from RPC');
158
+ }
159
+
160
+ const balanceBigInt = BigInt(lamports);
161
+ const aeth = lamportsToAeth(balanceBigInt);
162
+
163
+ if (asJson) {
164
+ console.log(JSON.stringify({
165
+ address,
166
+ lamports: balanceBigInt.toString(),
167
+ aeth: parseFloat(aeth),
168
+ rpc: options.rpc,
169
+ timestamp: new Date().toISOString(),
170
+ }, null, 2));
171
+ } else {
172
+ const shortAddr = shortenAddress(address);
173
+ console.log();
174
+ console.log(`${C.bright}Account Balance${C.reset}`);
175
+ console.log(`${C.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${C.reset}`);
176
+ console.log(`${C.cyan}Address:${C.reset} ${C.bright}${address}${C.reset}`);
177
+ console.log();
178
+
179
+ if (showLamports) {
180
+ console.log(`${C.green}${C.bright}${balanceBigInt.toString()}${C.reset} ${C.dim}lamports${C.reset}`);
181
+ } else {
182
+ console.log(`${C.green}${C.bright}${aeth}${C.reset} ${C.dim}AETH${C.reset}`);
183
+ console.log(`${C.dim}(${balanceBigInt.toString()} lamports)${C.reset}`);
184
+ }
185
+
186
+ console.log();
187
+ console.log(`${C.dim}RPC: ${options.rpc}${C.reset}`);
188
+ console.log(`${C.dim}Time: ${new Date().toLocaleString()}${C.reset}`);
189
+ console.log();
190
+ }
191
+
192
+ return { address, lamports: balanceBigInt, aeth: parseFloat(aeth) };
193
+ }
194
+
195
+ // ---------------------------------------------------------------------------
196
+ // Main command
197
+ // ---------------------------------------------------------------------------
198
+
199
+ async function balanceCommand() {
200
+ const options = parseArgs();
201
+ let address = options.address;
202
+
203
+ // If no address provided, try to use default wallet
204
+ if (!address) {
205
+ const config = loadConfig();
206
+ if (config.defaultWallet) {
207
+ address = config.defaultWallet;
208
+ if (!options.asJson) {
209
+ console.log(`${C.dim}Using default wallet: ${shortenAddress(address)}${C.reset}`);
210
+ }
211
+ } else {
212
+ const error = new Error('No address provided and no default wallet configured');
213
+ error.isValidationError = true;
214
+ throw error;
215
+ }
216
+ }
217
+
218
+ const client = createClient(options.rpc);
219
+
220
+ try {
221
+ await fetchBalance(client, address, options);
222
+ } catch (error) {
223
+ // Add context to error
224
+ if (!error.context) {
225
+ error.context = { address, rpc: options.rpc };
226
+ }
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ // Run with error handling
232
+ if (require.main === module) {
233
+ withErrorHandling(balanceCommand, { exit: true, verbose: process.env.AETHER_VERBOSE === '1' })();
234
+ }
235
+
236
+ module.exports = {
237
+ balanceCommand,
238
+ parseArgs,
239
+ fetchBalance,
240
+ loadConfig,
241
+ };
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aether-cli blockhash
4
+ *
5
+ * Fetches the latest recent blockhash from the Aether blockchain — required
6
+ * as a prerequisite for signing and submitting any transaction.
7
+ *
8
+ * Usage:
9
+ * aether-cli blockhash Show latest blockhash
10
+ * aether-cli blockhash --json JSON output for scripting
11
+ * aether-cli blockhash --rpc <url> Query a specific RPC endpoint
12
+ * aether-cli blockhash --watch Poll every 5 seconds
13
+ *
14
+ * Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
15
+ * SDK: @jellylegsai/aether-sdk — makes REAL HTTP RPC calls to the chain
16
+ */
17
+
18
+ const path = require('path');
19
+
20
+ // ANSI colours
21
+ const C = {
22
+ reset: '\x1b[0m',
23
+ bright: '\x1b[1m',
24
+ dim: '\x1b[2m',
25
+ red: '\x1b[31m',
26
+ green: '\x1b[32m',
27
+ yellow: '\x1b[33m',
28
+ cyan: '\x1b[36m',
29
+ magenta: '\x1b[35m',
30
+ };
31
+
32
+ // Import SDK — REAL blockchain RPC calls to http://127.0.0.1:8899
33
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
34
+ const aether = require(sdkPath);
35
+
36
+ const DEFAULT_RPC = process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Argument parsing
40
+ // ---------------------------------------------------------------------------
41
+
42
+ function parseArgs() {
43
+ const args = process.argv.slice(2);
44
+ const options = {
45
+ rpc: DEFAULT_RPC,
46
+ asJson: false,
47
+ watch: false,
48
+ };
49
+
50
+ for (let i = 0; i < args.length; i++) {
51
+ if (args[i] === '--rpc' || args[i] === '-r') {
52
+ options.rpc = args[++i];
53
+ } else if (args[i] === '--json' || args[i] === '-j') {
54
+ options.asJson = true;
55
+ } else if (args[i] === '--watch' || args[i] === '-w') {
56
+ options.watch = true;
57
+ } else if (args[i] === '--help' || args[i] === '-h') {
58
+ showHelp();
59
+ process.exit(0);
60
+ }
61
+ }
62
+
63
+ return options;
64
+ }
65
+
66
+ function showHelp() {
67
+ console.log(`
68
+ ${C.bright}${C.cyan}aether-cli blockhash${C.reset} - Get Latest Blockhash
69
+
70
+ ${C.bright}Usage:${C.reset}
71
+ aether-cli blockhash [options]
72
+
73
+ ${C.bright}Options:${C.reset}
74
+ --rpc <url> Query a specific RPC endpoint (default: http://127.0.0.1:8899)
75
+ --json, -j Output raw JSON for scripting
76
+ --watch, -w Poll every 5 seconds
77
+ --help, -h Show this help message
78
+
79
+ ${C.bright}Description:${C.reset}
80
+ Fetches the most recent blockhash from the Aether blockchain.
81
+ Blockhashes are required as a recent-ref entry when building
82
+ signed transactions (Transfer, Stake, Unstake, etc.).
83
+
84
+ Every call makes a REAL HTTP RPC request to the configured
85
+ Aether node — no caching, no stubs.
86
+
87
+ ${C.bright}Examples:${C.reset}
88
+ aether blockhash
89
+ aether blockhash --json
90
+ aether blockhash --watch
91
+ AETHER_RPC=https://my-node:8899 aether blockhash
92
+ `);
93
+ }
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Fetch and display blockhash from REAL chain via SDK
97
+ // ---------------------------------------------------------------------------
98
+
99
+ async function fetchBlockhash(rpc) {
100
+ const client = new aether.AetherClient({ rpcUrl: rpc });
101
+ const result = await client.getRecentBlockhash();
102
+ return result;
103
+ }
104
+
105
+ function printBlockhash(result, rpc) {
106
+ const { blockhash, lastValidBlockHeight } = result;
107
+
108
+ console.log(`\n${C.bright}${C.cyan}── Aether Blockhash ─────────────────────────────────────${C.reset}\n`);
109
+ console.log(` ${C.bright}Blockhash:${C.reset} ${C.magenta}${blockhash}${C.reset}`);
110
+ if (lastValidBlockHeight !== undefined) {
111
+ console.log(` ${C.bright}Last Valid Block Height:${C.reset} ${C.cyan}${lastValidBlockHeight.toLocaleString()}${C.reset}`);
112
+ }
113
+ console.log(` ${C.dim}RPC: ${rpc}${C.reset}\n`);
114
+ }
115
+
116
+ function printJson(result, rpc) {
117
+ console.log(JSON.stringify({
118
+ blockhash: result.blockhash,
119
+ lastValidBlockHeight: result.lastValidBlockHeight,
120
+ rpc,
121
+ cli_version: '1.0.0',
122
+ timestamp: new Date().toISOString(),
123
+ }));
124
+ }
125
+
126
+ // ---------------------------------------------------------------------------
127
+ // Main
128
+ // ---------------------------------------------------------------------------
129
+
130
+ async function main() {
131
+ const opts = parseArgs();
132
+ const { rpc, asJson, watch } = opts;
133
+
134
+ if (watch && !asJson) {
135
+ console.log(`${C.dim}Watching for new blockhashes every 5s (Ctrl+C to stop)…${C.reset}`);
136
+ console.log();
137
+ }
138
+
139
+ async function tick() {
140
+ try {
141
+ const result = await fetchBlockhash(rpc);
142
+ if (asJson) {
143
+ printJson(result, rpc);
144
+ } else if (!watch) {
145
+ printBlockhash(result, rpc);
146
+ } else {
147
+ process.stdout.write(`\r${C.dim}[${new Date().toISOString()}]${C.reset} blockhash: ${C.magenta}${result.blockhash}${C.reset} `);
148
+ }
149
+ } catch (err) {
150
+ if (asJson) {
151
+ console.log(JSON.stringify({ error: err.message, rpc }));
152
+ } else if (!watch) {
153
+ console.log(`${C.red}✗ Failed to fetch blockhash: ${err.message}${C.reset}`);
154
+ } else {
155
+ process.stdout.write(`\r${C.red}✗ ${err.message}${C.reset} `);
156
+ }
157
+ }
158
+ }
159
+
160
+ if (watch) {
161
+ await tick(); // immediate first run
162
+ // eslint-disable-next-line no-unmodified-loop-condition
163
+ while (true) {
164
+ await new Promise(r => setTimeout(r, 5000));
165
+ await tick();
166
+ }
167
+ } else {
168
+ await tick();
169
+ }
170
+ }
171
+
172
+ main().catch(err => {
173
+ console.error(`${C.red}✗ Blockhash command failed:${C.reset} ${err.message}`);
174
+ process.exit(1);
175
+ });
176
+
177
+ module.exports = { blockhashCommand: main };
178
+
179
+ if (require.main === module) {
180
+ main();
181
+ }