aether-hub 1.2.8 → 1.3.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.
- package/commands/claim.js +258 -292
- package/commands/delegations.js +412 -412
- package/commands/emergency.js +607 -667
- package/commands/multisig.js +47 -88
- package/commands/rewards.js +479 -866
- package/commands/stake-positions.js +205 -205
- package/commands/tx-history.js +346 -346
- package/index.js +31 -41
- package/package.json +3 -1
- package/sdk/README.md +210 -0
- package/sdk/index.js +1013 -0
- package/sdk/package.json +33 -0
- package/sdk/rpc.js +108 -0
- package/sdk/test.js +85 -0
- package/theme.js +211 -0
package/index.js
CHANGED
|
@@ -40,7 +40,11 @@ const { slotCommand } = require('./commands/slot');
|
|
|
40
40
|
const readline = require('readline');
|
|
41
41
|
|
|
42
42
|
// CLI version
|
|
43
|
-
const VERSION = '1.0
|
|
43
|
+
const VERSION = '1.3.0';
|
|
44
|
+
|
|
45
|
+
// Import shared theme
|
|
46
|
+
const theme = require('./theme');
|
|
47
|
+
const { C, BANNERS, ICONS } = theme;
|
|
44
48
|
|
|
45
49
|
// Parse args early to support flags on commands
|
|
46
50
|
function getCommandArgs() {
|
|
@@ -66,21 +70,17 @@ async function showMenu() {
|
|
|
66
70
|
|
|
67
71
|
const prompt = (q) => new Promise((res) => rl.question(q, res));
|
|
68
72
|
|
|
69
|
-
console.log(
|
|
70
|
-
TIER_COLORS.FULL + '\n ╔═══════════════════════════════════════════════╗\n' +
|
|
71
|
-
' ║ AETHER CHAIN — Validator Setup Wizard ║\n' +
|
|
72
|
-
' ╚═══════════════════════════════════════════════╝' + TIER_COLORS.reset + '\n'
|
|
73
|
-
);
|
|
73
|
+
console.log(BANNERS.compact + '\n');
|
|
74
74
|
|
|
75
75
|
console.log(' Welcome to AeTHer Chain. What would you like to do?\n');
|
|
76
|
-
console.log(
|
|
77
|
-
console.log(
|
|
78
|
-
console.log(
|
|
79
|
-
console.log(
|
|
80
|
-
console.log(
|
|
81
|
-
console.log(
|
|
82
|
-
console.log(
|
|
83
|
-
console.log(
|
|
76
|
+
console.log(` ${C.cyan}1)${C.reset} ${ICONS.active} ${C.bright}Doctor${C.reset} — Check if your system meets requirements`);
|
|
77
|
+
console.log(` ${C.cyan}2)${C.reset} 🚀 ${C.bright}Start${C.reset} — Begin validator onboarding (recommended)`);
|
|
78
|
+
console.log(` ${C.cyan}3)${C.reset} 📊 ${C.bright}Monitor${C.reset} — Watch live validator stats`);
|
|
79
|
+
console.log(` ${C.cyan}4)${C.reset} 📋 ${C.bright}Logs${C.reset} — Tail and colourise validator logs`);
|
|
80
|
+
console.log(` ${C.cyan}5)${C.reset} 📦 ${C.bright}SDK${C.reset} — Get SDK links and install tools`);
|
|
81
|
+
console.log(` ${C.cyan}6)${C.reset} 🌐 ${C.bright}Network${C.reset} — Aether network status (slot, peers, TPS)`);
|
|
82
|
+
console.log(` ${C.cyan}7)${C.reset} ❓ ${C.bright}Help${C.reset} — Show all commands\n`);
|
|
83
|
+
console.log(` ${C.dim}Type a number or command name. Press Ctrl+C to exit.\n`);
|
|
84
84
|
|
|
85
85
|
const VALID_CHOICES = ['1', '2', '3', '4', '5', '6', '7', 'doctor', 'init', 'monitor', 'logs', 'sdk', 'network', 'help'];
|
|
86
86
|
|
|
@@ -463,37 +463,27 @@ const COMMANDS = {
|
|
|
463
463
|
* Display help message with ASCII art
|
|
464
464
|
*/
|
|
465
465
|
function showHelp() {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
██╔████╔██║██║███████╗███████╗██║██║ ██║██╔██╗ ██║
|
|
470
|
-
██║╚██╔╝██║██║╚════██║╚════██║██║██║ ██║██║╚██╗██║
|
|
471
|
-
██║ ╚═╝ ██║██║███████║███████║██║╚██████╔╝██║ ╚████║
|
|
472
|
-
╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝
|
|
473
|
-
|
|
474
|
-
Validator CLI v${VERSION}
|
|
475
|
-
`.trim();
|
|
476
|
-
|
|
477
|
-
console.log(header);
|
|
478
|
-
console.log('\nUsage: aether-cli <command> [options]\n');
|
|
466
|
+
console.log(BANNERS.main);
|
|
467
|
+
console.log(`${C.bright}Validator CLI v${VERSION}${C.reset}\n`);
|
|
468
|
+
console.log(`Usage: aether <command> [options]\n`);
|
|
479
469
|
console.log('Commands:');
|
|
480
470
|
Object.entries(COMMANDS).forEach(([cmd, info]) => {
|
|
481
|
-
console.log(` ${cmd.padEnd(18)} ${info.description}`);
|
|
471
|
+
console.log(` ${C.cyan}${cmd.padEnd(18)}${C.reset} ${info.description}`);
|
|
482
472
|
});
|
|
483
473
|
console.log('\nExamples:');
|
|
484
|
-
console.log(
|
|
485
|
-
console.log(
|
|
486
|
-
console.log(
|
|
487
|
-
console.log(
|
|
488
|
-
console.log(
|
|
489
|
-
console.log(
|
|
490
|
-
console.log(
|
|
491
|
-
console.log(
|
|
492
|
-
console.log(
|
|
493
|
-
console.log(
|
|
494
|
-
console.log(
|
|
495
|
-
console.log(
|
|
496
|
-
console.log(
|
|
474
|
+
console.log(` ${C.cyan}aether doctor${C.reset} # Check system requirements`);
|
|
475
|
+
console.log(` ${C.cyan}aether init${C.reset} # Start onboarding wizard`);
|
|
476
|
+
console.log(` ${C.cyan}aether monitor${C.reset} # Real-time validator dashboard`);
|
|
477
|
+
console.log(` ${C.cyan}aether validator start${C.reset} # Start validator node`);
|
|
478
|
+
console.log(` ${C.cyan}aether validator status${C.reset} # Check validator status`);
|
|
479
|
+
console.log(` ${C.cyan}aether wallet balance${C.reset} # Query AETH balance`);
|
|
480
|
+
console.log(` ${C.cyan}aether network${C.reset} # Network status, peers, slot info`);
|
|
481
|
+
console.log(` ${C.cyan}aether network --peers${C.reset} # Detailed peer list`);
|
|
482
|
+
console.log(` ${C.cyan}aether tx history${C.reset} # Show transaction history`);
|
|
483
|
+
console.log(` ${C.cyan}aether price${C.reset} # AETH/USD price check`);
|
|
484
|
+
console.log(` ${C.cyan}aether --version${C.reset} # Show version`);
|
|
485
|
+
console.log(`\n${C.dim}Documentation: https://github.com/jelly-legs-ai/Jelly-legs-unsteady-workshop${C.reset}`);
|
|
486
|
+
console.log(`${C.dim}Spec: docs/MINING_VALIDATOR_TOOLS.md\n`);
|
|
497
487
|
}
|
|
498
488
|
|
|
499
489
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aether-hub",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "AeTHer Validator CLI — tiered validators (Full/Lite/Observer), system checks, onboarding, and node management",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"index.js",
|
|
12
|
+
"theme.js",
|
|
12
13
|
"commands/",
|
|
14
|
+
"sdk/",
|
|
13
15
|
"test/",
|
|
14
16
|
"README.md",
|
|
15
17
|
"LICENSE"
|
package/sdk/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# @jellylegsai/aether-sdk
|
|
2
|
+
|
|
3
|
+
Official Aether Blockchain SDK for Node.js. Every function makes **REAL HTTP RPC calls** to the Aether blockchain at `http://127.0.0.1:8899`. No stubs, no mocks.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @jellylegsai/aether-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or use locally from the `sdk/` folder in this repo:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const aether = require('./sdk');
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const aether = require('@jellylegsai/aether-sdk');
|
|
21
|
+
|
|
22
|
+
// Get current slot
|
|
23
|
+
const slot = await aether.getSlot();
|
|
24
|
+
console.log('Current slot:', slot);
|
|
25
|
+
|
|
26
|
+
// Get account balance
|
|
27
|
+
const balance = await aether.getBalance('ATH...');
|
|
28
|
+
console.log('Balance:', balance);
|
|
29
|
+
|
|
30
|
+
// Use custom RPC endpoint
|
|
31
|
+
const client = new aether.AetherClient({ rpcUrl: 'http://127.0.0.1:8899' });
|
|
32
|
+
const epoch = await client.getEpochInfo();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## SDK Architecture
|
|
36
|
+
|
|
37
|
+
- **`AetherClient`** — Full-featured blockchain client class. All methods make real HTTP calls.
|
|
38
|
+
- **Convenience functions** — Top-level exports for one-off queries using the default RPC.
|
|
39
|
+
- **Low-level RPC helpers** — `rpcGet` / `rpcPost` for custom requests.
|
|
40
|
+
|
|
41
|
+
Default RPC: `http://127.0.0.1:8899` (override via `AETHER_RPC` env or constructor option).
|
|
42
|
+
|
|
43
|
+
## AetherClient
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
const aether = require('@jellylegsai/aether-sdk');
|
|
47
|
+
|
|
48
|
+
const client = new aether.AetherClient({
|
|
49
|
+
rpcUrl: 'http://127.0.0.1:8899', // default
|
|
50
|
+
timeoutMs: 10000, // default: 10s
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API Reference
|
|
55
|
+
|
|
56
|
+
### Chain Queries
|
|
57
|
+
|
|
58
|
+
| Method | Returns | RPC Endpoint |
|
|
59
|
+
|--------|---------|--------------|
|
|
60
|
+
| `getSlot()` | `number` — current slot | `GET /v1/slot` |
|
|
61
|
+
| `getBlockHeight()` | `number` — block height | `GET /v1/blockheight` |
|
|
62
|
+
| `getEpochInfo()` | `object` — epoch + slot info | `GET /v1/epoch` |
|
|
63
|
+
| `getAccountInfo(address)` | `object` — lamports, owner, data | `GET /v1/account/:address` |
|
|
64
|
+
| `getBalance(address)` | `number` — lamports | `GET /v1/account/:address` |
|
|
65
|
+
| `getTransaction(signature)` | `object` — tx details | `GET /v1/transaction/:sig` |
|
|
66
|
+
| `getRecentTransactions(address, limit?)` | `array` — recent txs | `GET /v1/transactions/:address` |
|
|
67
|
+
| `getTokenAccounts(address)` | `array` — SPL token accounts | `GET /v1/tokens/:address` |
|
|
68
|
+
| `getStakeAccounts(address)` | `array` — stake accounts | `GET /v1/stake-accounts/:address` |
|
|
69
|
+
| `getStakePositions(address)` | `array` — delegations | `GET /v1/stake/:address` |
|
|
70
|
+
| `getRewards(address)` | `object` — staking rewards | `GET /v1/rewards/:address` |
|
|
71
|
+
| `getValidators()` | `array` — validator list | `GET /v1/validators` |
|
|
72
|
+
| `getValidatorAPY(validatorAddr)` | `object` — APY data | `GET /v1/validator/:addr/apy` |
|
|
73
|
+
| `getTPS()` | `number` — TPS | `GET /v1/tps` |
|
|
74
|
+
| `getSupply()` | `object` — total/circulating/non-circulating | `GET /v1/supply` |
|
|
75
|
+
| `getFees()` | `object` — fee estimates | `GET /v1/fees` |
|
|
76
|
+
| `getSlotProduction()` | `object` — slot production | `POST /v1/slot_production` |
|
|
77
|
+
| `getClusterPeers()` | `array` — peer list | `GET /v1/peers` |
|
|
78
|
+
| `getHealth()` | `string` — "ok" if healthy | `GET /v1/health` |
|
|
79
|
+
| `getVersion()` | `object` — node version | `GET /v1/version` |
|
|
80
|
+
|
|
81
|
+
### Blockhash (required for signing)
|
|
82
|
+
|
|
83
|
+
| Method | Returns | RPC Endpoint |
|
|
84
|
+
|--------|---------|--------------|
|
|
85
|
+
| `getRecentBlockhash()` | `{ blockhash, lastValidBlockHeight }` | `GET /v1/recent-blockhash` |
|
|
86
|
+
|
|
87
|
+
### Transaction Submission
|
|
88
|
+
|
|
89
|
+
| Method | Returns | RPC Endpoint |
|
|
90
|
+
|--------|---------|--------------|
|
|
91
|
+
| `sendTransaction(tx)` | `object` — receipt | `POST /v1/transaction` |
|
|
92
|
+
|
|
93
|
+
### Transaction Builders (build + submit)
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `transfer({ from, to, amount, nonce, signFn })` | Build + send a Transfer TX |
|
|
98
|
+
| `stake({ staker, validator, amount, signFn })` | Build + send a Stake TX |
|
|
99
|
+
| `unstake({ stakeAccount, amount, signFn })` | Build + send an Unstake TX |
|
|
100
|
+
| `claimRewards({ stakeAccount, signFn })` | Build + send a ClaimRewards TX |
|
|
101
|
+
| `createNFT({ creator, metadataUrl, royalties, signFn })` | Build + send a CreateNFT TX |
|
|
102
|
+
| `transferNFT({ from, nftId, to, signFn })` | Build + send a TransferNFT TX |
|
|
103
|
+
| `updateMetadata({ creator, nftId, metadataUrl, signFn })` | Build + send an UpdateMetadata TX |
|
|
104
|
+
|
|
105
|
+
Each builder fetches a fresh `blockhash` + current `slot` from the chain, then submits the signed transaction via `sendTransaction()`. All steps are real RPC calls.
|
|
106
|
+
|
|
107
|
+
## Convenience Functions
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
// All of these use the default RPC (http://127.0.0.1:8899)
|
|
111
|
+
const slot = await aether.getSlot();
|
|
112
|
+
const balance = await aether.getBalance('ATH...');
|
|
113
|
+
const epoch = await aether.getEpoch();
|
|
114
|
+
const tps = await aether.getTPS();
|
|
115
|
+
const supply = await aether.getSupply();
|
|
116
|
+
const fees = await aether.getFees();
|
|
117
|
+
const validators = await aether.getValidators();
|
|
118
|
+
const peers = await aether.getPeers();
|
|
119
|
+
const health = await aether.getHealth();
|
|
120
|
+
const { blockhash } = await aether.getRecentBlockhash();
|
|
121
|
+
const tx = await aether.getTransaction('sig...');
|
|
122
|
+
const txs = await aether.getRecentTransactions('ATH...', 20);
|
|
123
|
+
const stakePos = await aether.getStakePositions('ATH...');
|
|
124
|
+
const rewards = await aether.getRewards('ATH...');
|
|
125
|
+
const tokenAccts = await aether.getTokenAccounts('ATH...');
|
|
126
|
+
const stakeAccts = await aether.getStakeAccounts('ATH...');
|
|
127
|
+
const apy = await aether.getValidatorAPY('validatorAddr');
|
|
128
|
+
const pingResult = await aether.ping(); // { ok, latency, rpc }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Utilities
|
|
132
|
+
|
|
133
|
+
| Function | Description |
|
|
134
|
+
|----------|-------------|
|
|
135
|
+
| `createClient(options)` | Factory: create an `AetherClient` instance |
|
|
136
|
+
| `ping(rpcUrl?)` | Ping RPC, returns `{ ok, latency, rpc }` |
|
|
137
|
+
| `rpcGet(rpcUrl, path, timeout?)` | Low-level GET |
|
|
138
|
+
| `rpcPost(rpcUrl, path, body, timeout?)` | Low-level POST |
|
|
139
|
+
| `DEFAULT_RPC_URL` | `"http://127.0.0.1:8899"` |
|
|
140
|
+
| `DEFAULT_TIMEOUT_MS` | `10000` |
|
|
141
|
+
|
|
142
|
+
## CLI Integration
|
|
143
|
+
|
|
144
|
+
The SDK is wired into these CLI commands in `aether-cli`:
|
|
145
|
+
|
|
146
|
+
| CLI Command | SDK Method Used |
|
|
147
|
+
|-------------|----------------|
|
|
148
|
+
| `aether status` | `getEpochInfo`, `getSupply`, `getSlot`, `getBlockHeight`, `getClusterPeers`, `getVersion`, `getStakePositions`, `getRewards` |
|
|
149
|
+
| `aether network` | `getSlot`, `getBlockHeight`, `getClusterPeers`, `getValidators`, `getEpochInfo`, `getSupply`, `getTPS` |
|
|
150
|
+
| `aether blockhash` | `getRecentBlockhash` |
|
|
151
|
+
| `aether fees` | `getFees`, `getRecentBlockhash` |
|
|
152
|
+
| `aether tps` | `getTPS`, `getSlot` |
|
|
153
|
+
| `aether account` | `getAccountInfo`, `getBalance`, `getRecentTransactions`, `getStakePositions`, `getTokenAccounts`, `getStakeAccounts` |
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Environment variable
|
|
159
|
+
export AETHER_RPC=http://127.0.0.1:8899
|
|
160
|
+
|
|
161
|
+
# Or per-call
|
|
162
|
+
const client = new aether.AetherClient({ rpcUrl: 'http://custom:8899' });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Example: Full Dashboard
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
const aether = require('@jellylegsai/aether-sdk');
|
|
169
|
+
|
|
170
|
+
async function dashboard() {
|
|
171
|
+
const [slot, blockHeight, tps, supply, { blockhash }] = await Promise.all([
|
|
172
|
+
aether.getSlot(),
|
|
173
|
+
aether.getBlockHeight(),
|
|
174
|
+
aether.getTPS(),
|
|
175
|
+
aether.getSupply(),
|
|
176
|
+
aether.getRecentBlockhash(),
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
console.log('=== Aether Network Dashboard ===');
|
|
180
|
+
console.log(`Slot: ${slot}`);
|
|
181
|
+
console.log(`Block: ${blockHeight}`);
|
|
182
|
+
console.log(`TPS: ${tps}`);
|
|
183
|
+
console.log(`Total Supply: ${supply.total}`);
|
|
184
|
+
console.log(`Blockhash: ${blockhash}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
dashboard();
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Example: Check Staking Rewards
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const aether = require('@jellylegsai/aether-sdk');
|
|
194
|
+
|
|
195
|
+
async function checkRewards(walletAddress) {
|
|
196
|
+
const [stakePositions, rewards] = await Promise.all([
|
|
197
|
+
aether.getStakePositions(walletAddress),
|
|
198
|
+
aether.getRewards(walletAddress),
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
console.log(`Stake positions: ${stakePositions.length}`);
|
|
202
|
+
console.log(`Total rewards: ${rewards.total || rewards.amount} lamports`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
checkRewards('ATH...');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT © Jelly-legs AI Team
|