@jellylegsai/aether-cli 1.9.1 → 2.0.1
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/IMPLEMENTATION_REPORT.md +319 -0
- package/commands/blockheight.js +230 -0
- package/commands/call.js +981 -0
- package/commands/claim.js +98 -72
- package/commands/deploy.js +959 -0
- package/commands/index.js +88 -86
- package/commands/init.js +33 -49
- package/commands/network-diagnostics.js +706 -0
- package/commands/network.js +412 -429
- package/commands/rewards.js +311 -266
- package/commands/sdk.js +791 -656
- package/commands/slot.js +3 -11
- package/commands/stake.js +581 -516
- package/commands/supply.js +483 -391
- package/commands/token-accounts.js +275 -0
- package/commands/transfer.js +3 -11
- package/commands/unstake.js +3 -11
- package/commands/validator-start.js +681 -323
- package/commands/validator.js +959 -0
- package/commands/validators.js +623 -626
- package/commands/version.js +240 -0
- package/commands/wallet.js +17 -24
- package/cycle-report-issue-116.txt +165 -0
- package/index.js +501 -595
- package/lib/ui.js +623 -0
- package/package.json +83 -76
- package/sdk/index.d.ts +546 -0
- package/sdk/index.js +130 -0
- package/sdk/package.json +2 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* aether-cli token-accounts
|
|
4
|
+
*
|
|
5
|
+
* Get SPL token accounts for a wallet address.
|
|
6
|
+
* Uses @jellylegsai/aether-sdk for REAL HTTP RPC calls.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* aether token-accounts <address> List token accounts
|
|
10
|
+
* aether token-accounts --address <addr> List token accounts
|
|
11
|
+
* aether token-accounts --json JSON output
|
|
12
|
+
* aether token-accounts --rpc <url> Custom RPC endpoint
|
|
13
|
+
*
|
|
14
|
+
* RPC Endpoint: GET /v1/tokens/<address>
|
|
15
|
+
* SDK Function: sdk.getTokenAccounts()
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
|
|
22
|
+
// Import UI framework for consistent branding
|
|
23
|
+
const { BRANDING, C, indicators, startSpinner, stopSpinner, drawBox, drawTable,
|
|
24
|
+
success, error, warning, info, code, highlight, key, value } = require('../lib/ui');
|
|
25
|
+
|
|
26
|
+
const CLI_VERSION = '1.0.0';
|
|
27
|
+
|
|
28
|
+
// Import SDK — makes REAL HTTP RPC calls to the blockchain
|
|
29
|
+
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
30
|
+
const aether = require(sdkPath);
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Helpers
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
function getDefaultRpc() {
|
|
37
|
+
return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createClient(rpc) {
|
|
41
|
+
return new aether.AetherClient({ rpcUrl: rpc });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function loadConfig() {
|
|
45
|
+
const aetherDir = path.join(os.homedir(), '.aether');
|
|
46
|
+
const cfgPath = path.join(aetherDir, 'config.json');
|
|
47
|
+
if (!fs.existsSync(cfgPath)) return { defaultWallet: null };
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
50
|
+
} catch {
|
|
51
|
+
return { defaultWallet: null };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function shortenAddress(addr) {
|
|
56
|
+
if (!addr) return 'unknown';
|
|
57
|
+
if (addr.length <= 16) return addr;
|
|
58
|
+
return `${addr.slice(0, 8)}...${addr.slice(-8)}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function formatTokenAmount(amount, decimals = 9) {
|
|
62
|
+
const val = Number(amount) / Math.pow(10, decimals);
|
|
63
|
+
return val.toFixed(decimals > 6 ? 6 : decimals).replace(/\.?0+$/, '');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Argument parsing
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
function parseArgs() {
|
|
71
|
+
const args = process.argv.slice(2);
|
|
72
|
+
const options = {
|
|
73
|
+
rpc: getDefaultRpc(),
|
|
74
|
+
address: null,
|
|
75
|
+
asJson: false,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
for (let i = 0; i < args.length; i++) {
|
|
79
|
+
if (args[i] === '--json' || args[i] === '-j') {
|
|
80
|
+
options.asJson = true;
|
|
81
|
+
} else if (args[i] === '--rpc' || args[i] === '-r') {
|
|
82
|
+
options.rpc = args[++i];
|
|
83
|
+
} else if (args[i] === '--address' || args[i] === '-a') {
|
|
84
|
+
options.address = args[++i];
|
|
85
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
86
|
+
showHelp();
|
|
87
|
+
process.exit(0);
|
|
88
|
+
} else if (!args[i].startsWith('-') && !options.address) {
|
|
89
|
+
options.address = args[i];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Try default wallet if no address
|
|
94
|
+
if (!options.address) {
|
|
95
|
+
const config = loadConfig();
|
|
96
|
+
if (config.defaultWallet) {
|
|
97
|
+
options.address = config.defaultWallet;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return options;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function showHelp() {
|
|
105
|
+
console.log(BRANDING.logoCompact);
|
|
106
|
+
console.log(`
|
|
107
|
+
${C.bright}${C.cyan}aether-cli token-accounts${C.reset} — Get SPL token accounts
|
|
108
|
+
|
|
109
|
+
${C.bright}USAGE${C.reset}
|
|
110
|
+
aether token-accounts [address] [options]
|
|
111
|
+
aether token-accounts --address <addr> [options]
|
|
112
|
+
|
|
113
|
+
${C.bright}OPTIONS${C.reset}
|
|
114
|
+
-a, --address <addr> Wallet address (default: configured default)
|
|
115
|
+
-r, --rpc <url> RPC endpoint (default: ${getDefaultRpc()})
|
|
116
|
+
-j, --json Output as JSON
|
|
117
|
+
-h, --help Show this help
|
|
118
|
+
|
|
119
|
+
${C.bright}DESCRIPTION${C.reset}
|
|
120
|
+
Queries the Aether blockchain for all SPL token accounts
|
|
121
|
+
associated with a wallet address.
|
|
122
|
+
|
|
123
|
+
${C.bright}SDK METHOD${C.reset}
|
|
124
|
+
client.getTokenAccounts(address) → GET /v1/tokens/<address>
|
|
125
|
+
|
|
126
|
+
${C.bright}EXAMPLES${C.reset}
|
|
127
|
+
aether token-accounts ATHxxx... # List token accounts
|
|
128
|
+
aether token-accounts --json # JSON output
|
|
129
|
+
aether token-accounts --rpc https://custom-rpc:8899
|
|
130
|
+
`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Token accounts query - REAL RPC call via SDK
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
async function fetchTokenAccounts(rpc, address) {
|
|
138
|
+
const client = createClient(rpc);
|
|
139
|
+
const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
|
|
140
|
+
|
|
141
|
+
// Real RPC call: GET /v1/tokens/<address>
|
|
142
|
+
const tokens = await client.getTokenAccounts(rawAddr);
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
address,
|
|
146
|
+
tokens: tokens || [],
|
|
147
|
+
rpc,
|
|
148
|
+
timestamp: new Date().toISOString(),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Output formatters
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
function printTokenAccounts(data) {
|
|
157
|
+
const { address, tokens, rpc } = data;
|
|
158
|
+
|
|
159
|
+
console.log();
|
|
160
|
+
console.log(BRANDING.commandBanner('token-accounts', 'SPL Token Accounts'));
|
|
161
|
+
|
|
162
|
+
console.log(`\n ${key('Wallet:')} ${highlight(address)}`);
|
|
163
|
+
console.log(` ${key('RPC:')} ${C.dim}${rpc}${C.reset}\n`);
|
|
164
|
+
|
|
165
|
+
if (tokens.length === 0) {
|
|
166
|
+
console.log(` ${warning('No token accounts found for this wallet.')}\n`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Build table rows
|
|
171
|
+
const rows = tokens.map((t, i) => {
|
|
172
|
+
const mint = shortenAddress(t.mint || t.token_mint || 'unknown');
|
|
173
|
+
const amount = formatTokenAmount(t.amount || t.balance || 0, t.decimals || 9);
|
|
174
|
+
const decimals = t.decimals || 9;
|
|
175
|
+
const isFrozen = t.is_frozen || t.frozen ? indicators.warning : indicators.success;
|
|
176
|
+
|
|
177
|
+
return [
|
|
178
|
+
`${i + 1}`,
|
|
179
|
+
mint,
|
|
180
|
+
`${amount}`,
|
|
181
|
+
`${decimals}`,
|
|
182
|
+
isFrozen,
|
|
183
|
+
];
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
console.log(drawTable(
|
|
187
|
+
['#', 'Mint', 'Balance', 'Decimals', 'Status'],
|
|
188
|
+
rows,
|
|
189
|
+
{ headerColor: C.cyan + C.bright, borderColor: C.dim }
|
|
190
|
+
));
|
|
191
|
+
|
|
192
|
+
console.log(`\n ${key('Total Accounts:')} ${value(tokens.length)}`);
|
|
193
|
+
console.log(` ${C.dim}SDK: getTokenAccounts()${C.reset}\n`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function printJson(data) {
|
|
197
|
+
console.log(JSON.stringify({
|
|
198
|
+
address: data.address,
|
|
199
|
+
tokens: data.tokens,
|
|
200
|
+
total_accounts: data.tokens.length,
|
|
201
|
+
rpc: data.rpc,
|
|
202
|
+
timestamp: data.timestamp,
|
|
203
|
+
cli_version: CLI_VERSION,
|
|
204
|
+
sdk: '@jellylegsai/aether-sdk',
|
|
205
|
+
rpc_endpoint: `GET /v1/tokens/${data.address}`,
|
|
206
|
+
}, null, 2));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Main command
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
async function tokenAccountsCommand() {
|
|
214
|
+
const options = parseArgs();
|
|
215
|
+
const { rpc, address, asJson } = options;
|
|
216
|
+
|
|
217
|
+
if (!address) {
|
|
218
|
+
console.log(`\n${indicators.error} ${error('No address provided.')}`);
|
|
219
|
+
console.log(` ${C.dim}Usage: aether token-accounts <address>${C.reset}`);
|
|
220
|
+
console.log(` ${C.dim} aether token-accounts --address <address>${C.reset}`);
|
|
221
|
+
console.log(` ${C.dim} aether token-accounts --help for more info${C.reset}\n`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!asJson) {
|
|
226
|
+
startSpinner('Fetching token accounts');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
// Real blockchain RPC call via SDK
|
|
231
|
+
const data = await fetchTokenAccounts(rpc, address);
|
|
232
|
+
|
|
233
|
+
if (!asJson) {
|
|
234
|
+
stopSpinner(true, 'Token accounts retrieved');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (asJson) {
|
|
238
|
+
printJson(data);
|
|
239
|
+
} else {
|
|
240
|
+
printTokenAccounts(data);
|
|
241
|
+
}
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (!asJson) {
|
|
244
|
+
stopSpinner(false, 'Failed');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (asJson) {
|
|
248
|
+
console.log(JSON.stringify({
|
|
249
|
+
error: err.message,
|
|
250
|
+
address,
|
|
251
|
+
rpc,
|
|
252
|
+
timestamp: new Date().toISOString(),
|
|
253
|
+
}, null, 2));
|
|
254
|
+
} else {
|
|
255
|
+
console.log(`\n${indicators.error} ${error('Failed to fetch token accounts:')} ${err.message}`);
|
|
256
|
+
console.log(` ${C.dim}Address: ${address}${C.reset}`);
|
|
257
|
+
console.log(` ${C.dim}RPC: ${rpc}${C.reset}`);
|
|
258
|
+
console.log(` ${C.dim}Make sure the Aether node is running${C.reset}\n`);
|
|
259
|
+
}
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
// Exports
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
|
|
268
|
+
module.exports = { tokenAccountsCommand: tokenAccountsCommand };
|
|
269
|
+
|
|
270
|
+
if (require.main === module) {
|
|
271
|
+
tokenAccountsCommand().catch(err => {
|
|
272
|
+
console.error(`${indicators.error} ${error('Token-accounts command failed:')} ${err.message}`);
|
|
273
|
+
process.exit(1);
|
|
274
|
+
});
|
|
275
|
+
}
|
package/commands/transfer.js
CHANGED
|
@@ -18,17 +18,9 @@ const os = require('os');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const readline = require('readline');
|
|
20
20
|
|
|
21
|
-
//
|
|
22
|
-
const C
|
|
23
|
-
|
|
24
|
-
bright: '\x1b[1m',
|
|
25
|
-
dim: '\x1b[2m',
|
|
26
|
-
red: '\x1b[31m',
|
|
27
|
-
green: '\x1b[32m',
|
|
28
|
-
yellow: '\x1b[33m',
|
|
29
|
-
cyan: '\x1b[36m',
|
|
30
|
-
magenta: '\x1b[35m',
|
|
31
|
-
};
|
|
21
|
+
// Import UI framework for consistent branding
|
|
22
|
+
const { BRANDING, C, indicators, startSpinner, stopSpinner, drawBox,
|
|
23
|
+
success, error, warning, info, code, highlight } = require('../lib/ui');
|
|
32
24
|
|
|
33
25
|
// Import SDK — REAL blockchain RPC calls to http://127.0.0.1:8899
|
|
34
26
|
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
package/commands/unstake.js
CHANGED
|
@@ -29,17 +29,9 @@ const bip39 = require('bip39');
|
|
|
29
29
|
const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
|
|
30
30
|
const aether = require(sdkPath);
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
const C
|
|
34
|
-
|
|
35
|
-
bright: '\x1b[1m',
|
|
36
|
-
dim: '\x1b[2m',
|
|
37
|
-
red: '\x1b[31m',
|
|
38
|
-
green: '\x1b[32m',
|
|
39
|
-
yellow: '\x1b[33m',
|
|
40
|
-
cyan: '\x1b[36m',
|
|
41
|
-
magenta: '\x1b[35m',
|
|
42
|
-
};
|
|
32
|
+
// Import UI framework for consistent branding
|
|
33
|
+
const { BRANDING, C, indicators, startSpinner, stopSpinner, drawBox, drawTable,
|
|
34
|
+
success, error, warning, info, code, highlight, value } = require('../lib/ui');
|
|
43
35
|
|
|
44
36
|
const CLI_VERSION = '1.0.0';
|
|
45
37
|
const DERIVATION_PATH = "m/44'/7777777'/0'/0'";
|