aether-hub 1.1.3 → 1.1.5
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 +304 -0
- package/commands/wallet.js +97 -0
- package/index.js +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* aether-cli account
|
|
4
|
+
*
|
|
5
|
+
* Query detailed on-chain account data for any address.
|
|
6
|
+
* Shows lamports, owner, executable, rent epoch, and program-owned account keys.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* aether account --address <addr> Full account dump
|
|
10
|
+
* aether account --address <addr> --json JSON output for scripting
|
|
11
|
+
* aether account --address <addr> --data Show raw account data as base64/hex
|
|
12
|
+
*
|
|
13
|
+
* Requires AETHER_RPC env var (default: http://127.0.0.1:8899)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const http = require('http');
|
|
17
|
+
const https = require('https');
|
|
18
|
+
const bs58 = require('bs58').default;
|
|
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
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// HTTP helpers
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
function httpRequest(rpcUrl, path) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const url = new URL(path, rpcUrl);
|
|
39
|
+
const lib = url.protocol === 'https:' ? https : http;
|
|
40
|
+
const req = lib.request({
|
|
41
|
+
hostname: url.hostname,
|
|
42
|
+
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
43
|
+
path: url.pathname + url.search,
|
|
44
|
+
method: 'GET',
|
|
45
|
+
timeout: 8000,
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
}, (res) => {
|
|
48
|
+
let data = '';
|
|
49
|
+
res.on('data', (chunk) => data += chunk);
|
|
50
|
+
res.on('end', () => {
|
|
51
|
+
try { resolve(JSON.parse(data)); }
|
|
52
|
+
catch { resolve({ raw: data }); }
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
req.on('error', reject);
|
|
56
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
|
|
57
|
+
req.end();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getDefaultRpc() {
|
|
62
|
+
return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function formatAether(lamports) {
|
|
66
|
+
const aeth = lamports / 1e9;
|
|
67
|
+
if (aeth === 0) return '0 AETH';
|
|
68
|
+
return aeth.toFixed(4).replace(/\.?0+$/, '') + ' AETH';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Parse args
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
function parseArgs() {
|
|
76
|
+
return process.argv.slice(3); // [node, index.js, account, ...]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function findArg(args, ...flags) {
|
|
80
|
+
for (const flag of flags) {
|
|
81
|
+
const idx = args.indexOf(flag);
|
|
82
|
+
if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('-')) {
|
|
83
|
+
return { value: args[idx + 1], idx };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parseBoolArg(args, ...flags) {
|
|
90
|
+
return flags.some(f => args.includes(f));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Format helpers
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
function formatPubkey(key) {
|
|
98
|
+
if (!key) return '—';
|
|
99
|
+
if (Array.isArray(key)) {
|
|
100
|
+
// base64-like or raw bytes → treat as public key bytes
|
|
101
|
+
if (key.length === 32) return 'ATH' + bs58.encode(Buffer.from(key.slice(0, 32)));
|
|
102
|
+
return 'ATH' + bs58.encode(Buffer.from(key));
|
|
103
|
+
}
|
|
104
|
+
if (typeof key === 'string') {
|
|
105
|
+
if (key.startsWith('ATH')) return key;
|
|
106
|
+
// Assume base58
|
|
107
|
+
try { return 'ATH' + bs58.encode(bs58.decode(key)); }
|
|
108
|
+
catch { return key.substring(0, 16) + '...'; }
|
|
109
|
+
}
|
|
110
|
+
return String(key).substring(0, 16);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function base64ToHex(b64) {
|
|
114
|
+
try {
|
|
115
|
+
const buf = Buffer.from(b64, 'base64');
|
|
116
|
+
return buf.toString('hex');
|
|
117
|
+
} catch {
|
|
118
|
+
return b64;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function formatData(data) {
|
|
123
|
+
if (!data) return null;
|
|
124
|
+
if (typeof data === 'string') return data;
|
|
125
|
+
if (Array.isArray(data)) {
|
|
126
|
+
// raw bytes → hex
|
|
127
|
+
return Buffer.from(data).toString('hex');
|
|
128
|
+
}
|
|
129
|
+
return JSON.stringify(data);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Main account query
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
async function accountCommand() {
|
|
137
|
+
const args = parseArgs();
|
|
138
|
+
|
|
139
|
+
// Parse flags
|
|
140
|
+
const addrArg = findArg(args, '--address', '-a');
|
|
141
|
+
const asJson = parseBoolArg(args, '--json', '-j');
|
|
142
|
+
const showData = parseBoolArg(args, '--data', '-d');
|
|
143
|
+
const rpcArg = findArg(args, '--rpc', '-r');
|
|
144
|
+
const rpcUrl = rpcArg ? rpcArg.value : getDefaultRpc();
|
|
145
|
+
|
|
146
|
+
if (!addrArg) {
|
|
147
|
+
console.log(`\n ${C.red}✗ Missing --address flag.${C.reset}`);
|
|
148
|
+
console.log(`\n ${C.cyan}Usage:${C.reset}`);
|
|
149
|
+
console.log(` ${C.cyan}aether account --address <addr>${C.reset} Show account details`);
|
|
150
|
+
console.log(` ${C.cyan}aether account --address <addr> --json${C.reset} JSON output`);
|
|
151
|
+
console.log(` ${C.cyan}aether account --address <addr> --data${C.reset} Show raw account data`);
|
|
152
|
+
console.log(` ${C.cyan}aether account --address <addr> --rpc <url>${C.reset} Use custom RPC\n`);
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const rawAddress = addrArg.value;
|
|
157
|
+
const address = rawAddress.startsWith('ATH') ? rawAddress : rawAddress;
|
|
158
|
+
const apiAddress = rawAddress.startsWith('ATH') ? rawAddress.slice(3) : rawAddress;
|
|
159
|
+
|
|
160
|
+
if (!asJson) {
|
|
161
|
+
console.log(`\n${C.bright}${C.cyan}── Account Info ──────────────────────────────────────────${C.reset}\n`);
|
|
162
|
+
console.log(` ${C.green}★${C.reset} Address: ${C.bright}${address}${C.reset}`);
|
|
163
|
+
console.log(` ${C.dim} RPC: ${rpcUrl}${C.reset}`);
|
|
164
|
+
console.log();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const account = await httpRequest(rpcUrl, `/v1/account/${apiAddress}`);
|
|
169
|
+
|
|
170
|
+
if (!account || account.error) {
|
|
171
|
+
if (asJson) {
|
|
172
|
+
console.log(JSON.stringify({ address, error: account?.error || 'Account not found' }, null, 2));
|
|
173
|
+
} else {
|
|
174
|
+
console.log(` ${C.yellow}⚠ Account not found on chain or RPC error.${C.reset}`);
|
|
175
|
+
console.log(` ${C.dim} This is normal for addresses with no on-chain account.${C.reset}`);
|
|
176
|
+
console.log(` ${C.dim} RPC response: ${JSON.stringify(account?.error || account)}${C.reset}\n`);
|
|
177
|
+
}
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const lamports = account.lamports || account.lamports === 0 ? account.lamports : 0;
|
|
182
|
+
const owner = account.owner || null;
|
|
183
|
+
const executable = account.executable || false;
|
|
184
|
+
const rentEpoch = account.rent_epoch;
|
|
185
|
+
const data = account.data;
|
|
186
|
+
const dataLen = data ? (Array.isArray(data) ? data.length : typeof data === 'string' ? data.length : 0) : 0;
|
|
187
|
+
|
|
188
|
+
if (asJson) {
|
|
189
|
+
let ownerStr = null;
|
|
190
|
+
if (owner) {
|
|
191
|
+
if (Array.isArray(owner)) {
|
|
192
|
+
ownerStr = 'ATH' + bs58.encode(Buffer.from(owner.slice(0, 32)));
|
|
193
|
+
} else if (typeof owner === 'string') {
|
|
194
|
+
ownerStr = owner.startsWith('ATH') ? owner : 'ATH' + bs58.encode(bs58.decode(owner));
|
|
195
|
+
} else {
|
|
196
|
+
ownerStr = String(owner);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log(JSON.stringify({
|
|
201
|
+
address,
|
|
202
|
+
rpc: rpcUrl,
|
|
203
|
+
lamports,
|
|
204
|
+
lamports_formatted: formatAether(lamports),
|
|
205
|
+
owner: ownerStr,
|
|
206
|
+
executable,
|
|
207
|
+
rent_epoch: rentEpoch,
|
|
208
|
+
data_size: dataLen,
|
|
209
|
+
data: showData ? formatData(data) : null,
|
|
210
|
+
fetched_at: new Date().toISOString(),
|
|
211
|
+
}, null, 2));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Human-readable output
|
|
216
|
+
console.log(` ${C.green}✓${C.reset} Found on chain`);
|
|
217
|
+
console.log(` ${C.dim}────────────────────────────────────────${C.reset}`);
|
|
218
|
+
console.log(` ${C.dim} Balance:${C.reset} ${C.bright}${formatAether(lamports)}${C.reset} (${lamports.toLocaleString()} lamports)`);
|
|
219
|
+
|
|
220
|
+
if (owner) {
|
|
221
|
+
let ownerStr;
|
|
222
|
+
if (Array.isArray(owner)) {
|
|
223
|
+
ownerStr = 'ATH' + bs58.encode(Buffer.from(owner.slice(0, 32)));
|
|
224
|
+
} else if (typeof owner === 'string') {
|
|
225
|
+
ownerStr = owner.startsWith('ATH') ? owner : 'ATH' + bs58.encode(bs58.decode(owner));
|
|
226
|
+
} else {
|
|
227
|
+
ownerStr = String(owner);
|
|
228
|
+
}
|
|
229
|
+
console.log(` ${C.dim} Owner:${C.reset} ${C.cyan}${ownerStr}${C.reset}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log(` ${C.dim} Executable:${C.reset} ${C.bright}${(executable ? 'Yes' : 'No')}${C.reset}`);
|
|
233
|
+
if (rentEpoch !== undefined) {
|
|
234
|
+
console.log(` ${C.dim} Rent epoch:${C.reset} ${rentEpoch}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (dataLen > 0) {
|
|
238
|
+
console.log(` ${C.dim} Data size:${C.reset} ${C.bright}${dataLen} bytes${C.reset}`);
|
|
239
|
+
} else {
|
|
240
|
+
console.log(` ${C.dim} Data size:${C.reset} 0 bytes`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (showData && data) {
|
|
244
|
+
console.log();
|
|
245
|
+
console.log(` ${C.dim} Raw data (hex):${C.reset}`);
|
|
246
|
+
const hex = formatData(data);
|
|
247
|
+
// Pretty-print in 32-byte chunks
|
|
248
|
+
const chunks = hex.match(/.{1,64}/g) || [];
|
|
249
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
250
|
+
const offset = (i * 32).toString(16).padStart(8, '0');
|
|
251
|
+
console.log(` ${C.dim}${offset}:${C.reset} ${chunks[i]}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(` ${C.dim}────────────────────────────────────────${C.reset}`);
|
|
257
|
+
|
|
258
|
+
// Additional context: try to determine account type
|
|
259
|
+
let accountType = 'Unknown';
|
|
260
|
+
if (owner) {
|
|
261
|
+
const ownerStr = Array.isArray(owner)
|
|
262
|
+
? bs58.encode(Buffer.from(owner.slice(0, 32)))
|
|
263
|
+
: (typeof owner === 'string' && !owner.startsWith('ATH') ? owner : '');
|
|
264
|
+
// Known program IDs (these are common Aether program identifiers)
|
|
265
|
+
const knownPrograms = {
|
|
266
|
+
'STAKE': 'Stake Program',
|
|
267
|
+
'SYSTEM': 'System Program',
|
|
268
|
+
'VOTE': 'Vote Program',
|
|
269
|
+
'TOKEN': 'Token Program',
|
|
270
|
+
'MEMO': 'Memo Program',
|
|
271
|
+
};
|
|
272
|
+
const prog = knownPrograms[ownerStr.toUpperCase()];
|
|
273
|
+
if (prog) accountType = prog;
|
|
274
|
+
else if (executable) accountType = 'Executable Program';
|
|
275
|
+
else if (dataLen === 0) accountType = 'Empty Account (no data)';
|
|
276
|
+
else accountType = 'Data Account';
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
console.log(` ${C.dim} Account type:${C.reset} ${C.bright}${accountType}${C.reset}`);
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(` ${C.dim} Fetch via API:${C.reset} GET ${rpcUrl}/v1/account/${apiAddress}`);
|
|
282
|
+
console.log();
|
|
283
|
+
|
|
284
|
+
} catch (err) {
|
|
285
|
+
if (asJson) {
|
|
286
|
+
console.log(JSON.stringify({ address, error: err.message }, null, 2));
|
|
287
|
+
} else {
|
|
288
|
+
console.log(` ${C.red}✗ Failed to fetch account:${C.reset} ${err.message}`);
|
|
289
|
+
console.log(` ${C.dim} Is your validator running? RPC: ${rpcUrl}${C.reset}`);
|
|
290
|
+
console.log(` ${C.dim} Set custom RPC: AETHER_RPC=https://your-rpc-url${C.reset}\n`);
|
|
291
|
+
}
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
// Export & run
|
|
298
|
+
// ---------------------------------------------------------------------------
|
|
299
|
+
|
|
300
|
+
module.exports = { accountCommand };
|
|
301
|
+
|
|
302
|
+
if (require.main === module) {
|
|
303
|
+
accountCommand();
|
|
304
|
+
}
|
package/commands/wallet.js
CHANGED
|
@@ -1107,6 +1107,100 @@ async function txHistory(rl) {
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
1109
|
// ---------------------------------------------------------------------------
|
|
1110
|
+
// ---------------------------------------------------------------------------
|
|
1111
|
+
// EXPORT WALLET
|
|
1112
|
+
// Export wallet data for backup — public data by default, mnemonic with --mnemonic flag
|
|
1113
|
+
// ---------------------------------------------------------------------------
|
|
1114
|
+
|
|
1115
|
+
async function exportWallet(rl) {
|
|
1116
|
+
console.log(`\n${C.bright}${C.cyan}── Wallet Export ─────────────────────────────────────────${C.reset}\n`);
|
|
1117
|
+
|
|
1118
|
+
const args = process.argv.slice(4);
|
|
1119
|
+
let address = null;
|
|
1120
|
+
let asJson = false;
|
|
1121
|
+
let includeMnemonic = false;
|
|
1122
|
+
|
|
1123
|
+
const addrIdx = args.findIndex((a) => a === '--address' || a === '-a');
|
|
1124
|
+
if (addrIdx !== -1 && args[addrIdx + 1]) {
|
|
1125
|
+
address = args[addrIdx + 1];
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
asJson = args.includes('--json') || args.includes('-j');
|
|
1129
|
+
includeMnemonic = args.includes('--mnemonic') || args.includes('-m');
|
|
1130
|
+
|
|
1131
|
+
if (!address) {
|
|
1132
|
+
const cfg = loadConfig();
|
|
1133
|
+
address = cfg.defaultWallet;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
if (!address) {
|
|
1137
|
+
console.log(` ${C.red}✗ No wallet address specified and no default wallet set.${C.reset}`);
|
|
1138
|
+
console.log(` ${C.dim}Usage: aether wallet export --address <addr> [--mnemonic] [--json]${C.reset}\n`);
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const walletData = loadWallet(address);
|
|
1143
|
+
if (!walletData) {
|
|
1144
|
+
console.log(` ${C.red}✗ Wallet not found:${C.reset} ${address}`);
|
|
1145
|
+
console.log(` ${C.dim} Available wallets: ${C.cyan}aether wallet list${C.reset}\n`);
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
const exportData = {
|
|
1150
|
+
version: walletData.version || 1,
|
|
1151
|
+
address: walletData.address,
|
|
1152
|
+
public_key: walletData.public_key,
|
|
1153
|
+
derivation_path: walletData.derivation_path,
|
|
1154
|
+
created_at: walletData.created_at,
|
|
1155
|
+
source: 'aether-cli',
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// Mnemonic export requires interactive confirmation for security
|
|
1159
|
+
if (includeMnemonic) {
|
|
1160
|
+
console.log(` ${C.yellow}⚠ WARNING: You are about to export your SECRET MNEMONIC.${C.reset}`);
|
|
1161
|
+
console.log(` ${C.dim} Anyone with this phrase can access your funds.${C.reset}\n`);
|
|
1162
|
+
const confirmed = await question(rl, ` Type ${C.bright}EXPORT${C.reset} to confirm: `);
|
|
1163
|
+
if (confirmed.trim().toUpperCase() !== 'EXPORT') {
|
|
1164
|
+
console.log(`\n ${C.dim}Aborted. Mnemonic not exported.${C.reset}\n`);
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
console.log(` ${C.green}✓ Confirmed${C.reset}\n`);
|
|
1168
|
+
|
|
1169
|
+
// Re-derive mnemonic from keypair is NOT possible — we must ask for it
|
|
1170
|
+
console.log(` ${C.dim}The CLI cannot retrieve your mnemonic from the stored keypair.${C.reset}`);
|
|
1171
|
+
console.log(` ${C.dim}If you have a backup of your mnemonic, enter it below to include it.${C.reset}`);
|
|
1172
|
+
console.log(` ${C.dim}Otherwise, press Enter to export public data only.${C.reset}\n`);
|
|
1173
|
+
const mnemonicInput = await question(rl, ` ${C.cyan}Mnemonic (or Enter to skip):${C.reset} `);
|
|
1174
|
+
const mnemonic = mnemonicInput.trim();
|
|
1175
|
+
if (mnemonic && bip39.validateMnemonic(mnemonic)) {
|
|
1176
|
+
exportData.mnemonic = mnemonic;
|
|
1177
|
+
} else if (mnemonic) {
|
|
1178
|
+
console.log(` ${C.red}✗ Invalid mnemonic phrase. Skipping.${C.reset}`);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
if (asJson) {
|
|
1183
|
+
console.log(JSON.stringify(exportData, null, 2));
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// Human-readable output
|
|
1188
|
+
console.log(` ${C.green}★${C.reset} Wallet exported successfully\n`);
|
|
1189
|
+
console.log(` ${C.dim}Address:${C.reset} ${exportData.address}`);
|
|
1190
|
+
console.log(` ${C.dim}Public key:${C.reset} ${exportData.public_key}`);
|
|
1191
|
+
console.log(` ${C.dim}Derivation path:${C.reset} ${exportData.derivation_path}`);
|
|
1192
|
+
console.log(` ${C.dim}Created:${C.reset} ${exportData.created_at ? new Date(exportData.created_at).toLocaleString() : 'unknown'}`);
|
|
1193
|
+
if (exportData.mnemonic) {
|
|
1194
|
+
console.log();
|
|
1195
|
+
console.log(` ${C.yellow}★ MNEMONIC (keep this secret!):${C.reset}`);
|
|
1196
|
+
console.log(` ${C.bright}${exportData.mnemonic}${C.reset}`);
|
|
1197
|
+
}
|
|
1198
|
+
console.log();
|
|
1199
|
+
console.log(` ${C.dim}Export saved to stdout in JSON format with:${C.reset}`);
|
|
1200
|
+
console.log(` ${C.cyan}aether wallet export --address ${address} --json${C.reset}`);
|
|
1201
|
+
console.log();
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1110
1204
|
// STAKE POSITIONS
|
|
1111
1205
|
// Query and display current stake positions/delegations for a wallet
|
|
1112
1206
|
// ---------------------------------------------------------------------------
|
|
@@ -1437,6 +1531,8 @@ async function walletCommand() {
|
|
|
1437
1531
|
await stakeWallet(rl);
|
|
1438
1532
|
} else if (subcmd === 'stake-positions') {
|
|
1439
1533
|
await stakePositions(rl);
|
|
1534
|
+
} else if (subcmd === 'export') {
|
|
1535
|
+
await exportWallet(rl);
|
|
1440
1536
|
} else if (subcmd === 'unstake') {
|
|
1441
1537
|
await unstakeWallet(rl);
|
|
1442
1538
|
} else if (subcmd === 'transfer') {
|
|
@@ -1449,6 +1545,7 @@ async function walletCommand() {
|
|
|
1449
1545
|
console.log(` ${C.cyan}aether wallet create${C.reset} Create new or import wallet`);
|
|
1450
1546
|
console.log(` ${C.cyan}aether wallet list${C.reset} List all wallets`);
|
|
1451
1547
|
console.log(` ${C.cyan}aether wallet import${C.reset} Import wallet from mnemonic`);
|
|
1548
|
+
console.log(` ${C.cyan}aether wallet export${C.reset} Export wallet data (pubkey, address) — --mnemonic to include phrase`);
|
|
1452
1549
|
console.log(` ${C.cyan}aether wallet default${C.reset} Show/set default wallet`);
|
|
1453
1550
|
console.log(` ${C.cyan}aether wallet connect${C.reset} Connect wallet via browser verification`);
|
|
1454
1551
|
console.log(` ${C.cyan}aether wallet balance${C.reset} Query chain balance for an address`);
|
package/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const { networkCommand } = require('./commands/network');
|
|
|
19
19
|
const { validatorsListCommand } = require('./commands/validators');
|
|
20
20
|
const { delegationsCommand } = require('./commands/delegations');
|
|
21
21
|
const { rewardsCommand } = require('./commands/rewards');
|
|
22
|
+
const { accountCommand } = require('./commands/account');
|
|
22
23
|
const { emergencyCommand } = require('./commands/emergency');
|
|
23
24
|
const readline = require('readline');
|
|
24
25
|
|
|
@@ -207,6 +208,16 @@ const COMMANDS = {
|
|
|
207
208
|
process.argv = originalArgv;
|
|
208
209
|
},
|
|
209
210
|
},
|
|
211
|
+
export: {
|
|
212
|
+
description: 'Export wallet data — aether export --address <addr> [--mnemonic] [--json]',
|
|
213
|
+
handler: () => {
|
|
214
|
+
const { walletCommand } = require('./commands/wallet');
|
|
215
|
+
const originalArgv = process.argv;
|
|
216
|
+
process.argv = [...originalArgv.slice(0, 2), 'wallet', 'export', ...originalArgv.slice(3)];
|
|
217
|
+
walletCommand();
|
|
218
|
+
process.argv = originalArgv;
|
|
219
|
+
},
|
|
220
|
+
},
|
|
210
221
|
transfer: {
|
|
211
222
|
description: 'Transfer AETH to another address — aether transfer --to <addr> --amount <aeth>',
|
|
212
223
|
handler: () => {
|
|
@@ -293,6 +304,13 @@ const COMMANDS = {
|
|
|
293
304
|
snapshotCommand();
|
|
294
305
|
},
|
|
295
306
|
},
|
|
307
|
+
account: {
|
|
308
|
+
description: 'Query on-chain account data — aether account --address <addr> [--json] [--data] [--rpc <url>]',
|
|
309
|
+
handler: () => {
|
|
310
|
+
const { accountCommand } = require('./commands/account');
|
|
311
|
+
accountCommand();
|
|
312
|
+
},
|
|
313
|
+
},
|
|
296
314
|
validators: {
|
|
297
315
|
description: 'List active validators — aether validators list [--tier full|lite|observer] [--json]',
|
|
298
316
|
handler: () => {
|