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/sdk/index.js
ADDED
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jellylegsai/aether-sdk
|
|
3
|
+
*
|
|
4
|
+
* Official Aether Blockchain SDK - Real HTTP RPC calls to Aether nodes
|
|
5
|
+
* No stubs, no mocks - every function makes actual blockchain calls
|
|
6
|
+
*
|
|
7
|
+
* Default RPC: http://127.0.0.1:8899 (configurable via constructor or AETHER_RPC env)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const http = require('http');
|
|
11
|
+
const https = require('https');
|
|
12
|
+
|
|
13
|
+
// Default configuration
|
|
14
|
+
const DEFAULT_RPC_URL = 'http://127.0.0.1:8899';
|
|
15
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Aether SDK Client
|
|
19
|
+
* Real blockchain interface layer - every method makes actual HTTP RPC calls
|
|
20
|
+
*/
|
|
21
|
+
class AetherClient {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.rpcUrl = options.rpcUrl || process.env.AETHER_RPC || DEFAULT_RPC_URL;
|
|
24
|
+
this.timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS;
|
|
25
|
+
|
|
26
|
+
// Parse RPC URL
|
|
27
|
+
const url = new URL(this.rpcUrl);
|
|
28
|
+
this.protocol = url.protocol;
|
|
29
|
+
this.hostname = url.hostname;
|
|
30
|
+
this.port = url.port || (this.protocol === 'https:' ? 443 : 80);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Internal: Make HTTP GET request to RPC endpoint
|
|
35
|
+
*/
|
|
36
|
+
_httpGet(path, timeoutMs = this.timeoutMs) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const lib = this.protocol === 'https:' ? https : http;
|
|
39
|
+
const req = lib.request({
|
|
40
|
+
hostname: this.hostname,
|
|
41
|
+
port: this.port,
|
|
42
|
+
path: path,
|
|
43
|
+
method: 'GET',
|
|
44
|
+
timeout: timeoutMs,
|
|
45
|
+
headers: { 'Content-Type': 'application/json' },
|
|
46
|
+
}, (res) => {
|
|
47
|
+
let data = '';
|
|
48
|
+
res.on('data', (chunk) => data += chunk);
|
|
49
|
+
res.on('end', () => {
|
|
50
|
+
try {
|
|
51
|
+
const parsed = JSON.parse(data);
|
|
52
|
+
if (parsed.error) {
|
|
53
|
+
reject(new Error(parsed.error.message || JSON.stringify(parsed.error)));
|
|
54
|
+
} else {
|
|
55
|
+
resolve(parsed);
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
resolve({ raw: data });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
req.on('error', reject);
|
|
63
|
+
req.on('timeout', () => {
|
|
64
|
+
req.destroy();
|
|
65
|
+
reject(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
66
|
+
});
|
|
67
|
+
req.end();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Internal: Make HTTP POST request to RPC endpoint
|
|
73
|
+
*/
|
|
74
|
+
_httpPost(path, body = {}, timeoutMs = this.timeoutMs) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const lib = this.protocol === 'https:' ? https : http;
|
|
77
|
+
const bodyStr = JSON.stringify(body);
|
|
78
|
+
const req = lib.request({
|
|
79
|
+
hostname: this.hostname,
|
|
80
|
+
port: this.port,
|
|
81
|
+
path: path,
|
|
82
|
+
method: 'POST',
|
|
83
|
+
timeout: timeoutMs,
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
'Content-Length': Buffer.byteLength(bodyStr),
|
|
87
|
+
},
|
|
88
|
+
}, (res) => {
|
|
89
|
+
let data = '';
|
|
90
|
+
res.on('data', (chunk) => data += chunk);
|
|
91
|
+
res.on('end', () => {
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(data);
|
|
94
|
+
if (parsed.error) {
|
|
95
|
+
reject(new Error(parsed.error.message || JSON.stringify(parsed.error)));
|
|
96
|
+
} else {
|
|
97
|
+
resolve(parsed);
|
|
98
|
+
}
|
|
99
|
+
} catch (e) {
|
|
100
|
+
resolve({ raw: data });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
req.on('error', reject);
|
|
105
|
+
req.on('timeout', () => {
|
|
106
|
+
req.destroy();
|
|
107
|
+
reject(new Error(`Request timeout after ${timeoutMs}ms`));
|
|
108
|
+
});
|
|
109
|
+
req.write(bodyStr);
|
|
110
|
+
req.end();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ============================================================
|
|
115
|
+
// Core RPC Methods - Real blockchain calls
|
|
116
|
+
// ============================================================
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get current slot number
|
|
120
|
+
* RPC: GET /v1/slot
|
|
121
|
+
*
|
|
122
|
+
* @returns {Promise<number>} Current slot number
|
|
123
|
+
*/
|
|
124
|
+
async getSlot() {
|
|
125
|
+
const result = await this._httpGet('/v1/slot');
|
|
126
|
+
return result.slot !== undefined ? result.slot : result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get current block height
|
|
131
|
+
* RPC: GET /v1/blockheight
|
|
132
|
+
*
|
|
133
|
+
* @returns {Promise<number>} Current block height
|
|
134
|
+
*/
|
|
135
|
+
async getBlockHeight() {
|
|
136
|
+
const result = await this._httpGet('/v1/blockheight');
|
|
137
|
+
return result.blockHeight !== undefined ? result.blockHeight : result;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get account info including balance
|
|
142
|
+
* RPC: GET /v1/account/<address>
|
|
143
|
+
*
|
|
144
|
+
* @param {string} address - Account public key (base58)
|
|
145
|
+
* @returns {Promise<Object>} Account info: { lamports, owner, data, rent_epoch }
|
|
146
|
+
*/
|
|
147
|
+
async getAccountInfo(address) {
|
|
148
|
+
if (!address) {
|
|
149
|
+
throw new Error('Address is required');
|
|
150
|
+
}
|
|
151
|
+
const result = await this._httpGet(`/v1/account/${address}`);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Alias for getAccountInfo
|
|
157
|
+
* @param {string} address - Account address
|
|
158
|
+
* @returns {Promise<Object>} Account info
|
|
159
|
+
*/
|
|
160
|
+
async getAccount(address) {
|
|
161
|
+
return this.getAccountInfo(address);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get balance in lamports
|
|
166
|
+
* RPC: GET /v1/account/<address>
|
|
167
|
+
*
|
|
168
|
+
* @param {string} address - Account public key (base58)
|
|
169
|
+
* @returns {Promise<number>} Balance in lamports
|
|
170
|
+
*/
|
|
171
|
+
async getBalance(address) {
|
|
172
|
+
const account = await this.getAccountInfo(address);
|
|
173
|
+
return account.lamports !== undefined ? account.lamports : 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get epoch info
|
|
178
|
+
* RPC: GET /v1/epoch
|
|
179
|
+
*
|
|
180
|
+
* @returns {Promise<Object>} Epoch info: { epoch, slotIndex, slotsInEpoch, absoluteSlot }
|
|
181
|
+
*/
|
|
182
|
+
async getEpochInfo() {
|
|
183
|
+
const result = await this._httpGet('/v1/epoch');
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get transaction by signature
|
|
189
|
+
* RPC: GET /v1/transaction/<signature>
|
|
190
|
+
*
|
|
191
|
+
* @param {string} signature - Transaction signature (base58)
|
|
192
|
+
* @returns {Promise<Object>} Transaction details
|
|
193
|
+
*/
|
|
194
|
+
async getTransaction(signature) {
|
|
195
|
+
if (!signature) {
|
|
196
|
+
throw new Error('Transaction signature is required');
|
|
197
|
+
}
|
|
198
|
+
const result = await this._httpGet(`/v1/transaction/${signature}`);
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Submit a signed transaction
|
|
204
|
+
* RPC: POST /v1/transaction
|
|
205
|
+
*
|
|
206
|
+
* @param {Object} tx - Signed transaction object
|
|
207
|
+
* @param {string} tx.signature - Transaction signature (base58)
|
|
208
|
+
* @param {string} tx.signer - Signer public key (base58)
|
|
209
|
+
* @param {string} tx.tx_type - Transaction type
|
|
210
|
+
* @param {Object} tx.payload - Transaction payload
|
|
211
|
+
* @returns {Promise<Object>} Transaction receipt: { signature, slot, confirmed }
|
|
212
|
+
*/
|
|
213
|
+
async sendTransaction(tx) {
|
|
214
|
+
if (!tx || !tx.signature) {
|
|
215
|
+
throw new Error('Transaction with signature is required');
|
|
216
|
+
}
|
|
217
|
+
const result = await this._httpPost('/v1/transaction', tx);
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get recent blockhash for transaction signing
|
|
223
|
+
* RPC: GET /v1/recent-blockhash
|
|
224
|
+
*
|
|
225
|
+
* @returns {Promise<Object>} { blockhash, lastValidBlockHeight }
|
|
226
|
+
*/
|
|
227
|
+
async getRecentBlockhash() {
|
|
228
|
+
const result = await this._httpGet('/v1/recent-blockhash');
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get network peers
|
|
234
|
+
* RPC: GET /v1/peers
|
|
235
|
+
*
|
|
236
|
+
* @returns {Promise<Array>} List of peer node addresses
|
|
237
|
+
*/
|
|
238
|
+
async getClusterPeers() {
|
|
239
|
+
const result = await this._httpGet('/v1/peers');
|
|
240
|
+
return Array.isArray(result) ? result : (result.peers || []);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get validator info
|
|
245
|
+
* RPC: GET /v1/validators
|
|
246
|
+
*
|
|
247
|
+
* @returns {Promise<Array>} List of validators with stake, commission, etc.
|
|
248
|
+
*/
|
|
249
|
+
async getValidators() {
|
|
250
|
+
const result = await this._httpGet('/v1/validators');
|
|
251
|
+
return Array.isArray(result) ? result : (result.validators || []);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Get supply info
|
|
256
|
+
* RPC: GET /v1/supply
|
|
257
|
+
*
|
|
258
|
+
* @returns {Promise<Object>} Supply info: { total, circulating, nonCirculating }
|
|
259
|
+
*/
|
|
260
|
+
async getSupply() {
|
|
261
|
+
const result = await this._httpGet('/v1/supply');
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get health status
|
|
267
|
+
* RPC: GET /v1/health
|
|
268
|
+
*
|
|
269
|
+
* @returns {Promise<string>} 'ok' if node is healthy
|
|
270
|
+
*/
|
|
271
|
+
async getHealth() {
|
|
272
|
+
const result = await this._httpGet('/v1/health');
|
|
273
|
+
return result.status || result;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get version info
|
|
278
|
+
* RPC: GET /v1/version
|
|
279
|
+
*
|
|
280
|
+
* @returns {Promise<Object>} Version info: { aetherCore, featureSet }
|
|
281
|
+
*/
|
|
282
|
+
async getVersion() {
|
|
283
|
+
const result = await this._httpGet('/v1/version');
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get TPS (transactions per second)
|
|
289
|
+
* RPC: GET /v1/tps
|
|
290
|
+
*
|
|
291
|
+
* @returns {Promise<number>} Current TPS
|
|
292
|
+
*/
|
|
293
|
+
async getTPS() {
|
|
294
|
+
const result = await this._httpGet('/v1/tps');
|
|
295
|
+
return result.tps ?? result.tps_avg ?? result.transactions_per_second ?? null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get fee estimates
|
|
300
|
+
* RPC: GET /v1/fees
|
|
301
|
+
*
|
|
302
|
+
* @returns {Promise<Object>} Fee info
|
|
303
|
+
*/
|
|
304
|
+
async getFees() {
|
|
305
|
+
const result = await this._httpGet('/v1/fees');
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Get slot production stats
|
|
311
|
+
* RPC: POST /v1/slot_production
|
|
312
|
+
*
|
|
313
|
+
* @returns {Promise<Object>} Slot production stats
|
|
314
|
+
*/
|
|
315
|
+
async getSlotProduction() {
|
|
316
|
+
const result = await this._httpPost('/v1/slot_production', {});
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get stake positions for an address
|
|
322
|
+
* RPC: GET /v1/stake/<address>
|
|
323
|
+
*
|
|
324
|
+
* @param {string} address - Account address
|
|
325
|
+
* @returns {Promise<Array>} List of stake positions
|
|
326
|
+
*/
|
|
327
|
+
async getStakePositions(address) {
|
|
328
|
+
if (!address) throw new Error('Address is required');
|
|
329
|
+
const result = await this._httpGet(`/v1/stake/${address}`);
|
|
330
|
+
return result.delegations ?? result.stakes ?? result ?? [];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Get rewards for an address
|
|
335
|
+
* RPC: GET /v1/rewards/<address>
|
|
336
|
+
*
|
|
337
|
+
* @param {string} address - Account address
|
|
338
|
+
* @returns {Promise<Object>} Rewards info
|
|
339
|
+
*/
|
|
340
|
+
async getRewards(address) {
|
|
341
|
+
if (!address) throw new Error('Address is required');
|
|
342
|
+
const result = await this._httpGet(`/v1/rewards/${address}`);
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Get validator APY
|
|
348
|
+
* RPC: GET /v1/validator/<address>/apy
|
|
349
|
+
*
|
|
350
|
+
* @param {string} validatorAddr - Validator address
|
|
351
|
+
* @returns {Promise<Object>} APY info
|
|
352
|
+
*/
|
|
353
|
+
async getValidatorAPY(validatorAddr) {
|
|
354
|
+
if (!validatorAddr) throw new Error('Validator address is required');
|
|
355
|
+
const result = await this._httpGet(`/v1/validator/${validatorAddr}/apy`);
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get recent transactions for an address
|
|
361
|
+
* RPC: GET /v1/transactions/<address>?limit=<n>
|
|
362
|
+
*
|
|
363
|
+
* @param {string} address - Account address
|
|
364
|
+
* @param {number} limit - Max transactions to return
|
|
365
|
+
* @returns {Promise<Array>} List of recent transactions
|
|
366
|
+
*/
|
|
367
|
+
async getRecentTransactions(address, limit = 20) {
|
|
368
|
+
if (!address) throw new Error('Address is required');
|
|
369
|
+
const result = await this._httpGet(`/v1/transactions/${address}?limit=${limit}`);
|
|
370
|
+
return result.transactions ?? result ?? [];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get transaction history with signatures for an address
|
|
375
|
+
* RPC: POST /v1/transactions/history (or GET /v1/transactions/<address>?limit=<n>)
|
|
376
|
+
*
|
|
377
|
+
* @param {string} address - Account address
|
|
378
|
+
* @param {number} limit - Max transactions to return
|
|
379
|
+
* @returns {Promise<Object>} Transaction history with signatures and details
|
|
380
|
+
*/
|
|
381
|
+
async getTransactionHistory(address, limit = 20) {
|
|
382
|
+
if (!address) throw new Error('Address is required');
|
|
383
|
+
// First get signatures
|
|
384
|
+
const sigResult = await this._httpPost('/v1/transactions/history', { address, limit });
|
|
385
|
+
if (sigResult.error) {
|
|
386
|
+
throw new Error(sigResult.error.message || sigResult.error);
|
|
387
|
+
}
|
|
388
|
+
const signatures = sigResult.signatures || sigResult.result || [];
|
|
389
|
+
|
|
390
|
+
// Fetch full transaction details for each signature (up to 10 at a time)
|
|
391
|
+
const BATCH = 10;
|
|
392
|
+
const txs = [];
|
|
393
|
+
for (let i = 0; i < signatures.length; i += BATCH) {
|
|
394
|
+
const batch = signatures.slice(i, i + BATCH);
|
|
395
|
+
const batchPromises = batch.map(sig =>
|
|
396
|
+
this.getTransaction(sig.signature || sig).catch(() => null)
|
|
397
|
+
);
|
|
398
|
+
const batchResults = await Promise.all(batchPromises);
|
|
399
|
+
txs.push(...batchResults.filter(Boolean));
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
signatures: signatures,
|
|
404
|
+
transactions: txs,
|
|
405
|
+
address: address,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Get all SPL token accounts for a wallet address
|
|
411
|
+
* RPC: GET /v1/tokens/<address>
|
|
412
|
+
*
|
|
413
|
+
* @param {string} address - Account public key (base58)
|
|
414
|
+
* @returns {Promise<Array>} List of token accounts with mint, amount, decimals
|
|
415
|
+
*/
|
|
416
|
+
async getTokenAccounts(address) {
|
|
417
|
+
if (!address) throw new Error('Address is required');
|
|
418
|
+
const result = await this._httpGet(`/v1/tokens/${address}`);
|
|
419
|
+
return result.tokens ?? result.accounts ?? result ?? [];
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get all stake accounts for a wallet address
|
|
424
|
+
* RPC: GET /v1/stake-accounts/<address>
|
|
425
|
+
*
|
|
426
|
+
* @param {string} address - Account public key (base58)
|
|
427
|
+
* @returns {Promise<Array>} List of stake accounts
|
|
428
|
+
*/
|
|
429
|
+
async getStakeAccounts(address) {
|
|
430
|
+
if (!address) throw new Error('Address is required');
|
|
431
|
+
const result = await this._httpGet(`/v1/stake-accounts/${address}`);
|
|
432
|
+
return result.stake_accounts ?? result.delegations ?? result ?? [];
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// ============================================================
|
|
436
|
+
// Transaction Helpers - Build and send real transactions
|
|
437
|
+
// ============================================================
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Build and send a transfer transaction
|
|
441
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
442
|
+
*
|
|
443
|
+
* @param {Object} params
|
|
444
|
+
* @param {string} params.from - Sender address (base58)
|
|
445
|
+
* @param {string} params.to - Recipient address (base58)
|
|
446
|
+
* @param {number} params.amount - Amount in lamports
|
|
447
|
+
* @param {number} params.nonce - Nonce for replay protection
|
|
448
|
+
* @param {Function} params.signFn - Function to sign the transaction (receives tx object, returns signature)
|
|
449
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
450
|
+
*/
|
|
451
|
+
async transfer({ from, to, amount, nonce, signFn }) {
|
|
452
|
+
if (!from || !to || !amount === undefined || nonce === undefined) {
|
|
453
|
+
throw new Error('from, to, amount, and nonce are required');
|
|
454
|
+
}
|
|
455
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
456
|
+
throw new Error('signFn is required (function to sign the transaction)');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Get recent blockhash (real RPC call)
|
|
460
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
461
|
+
|
|
462
|
+
// Build transaction payload
|
|
463
|
+
const tx = {
|
|
464
|
+
signature: '', // Will be filled after signing
|
|
465
|
+
signer: from,
|
|
466
|
+
tx_type: 'Transfer',
|
|
467
|
+
payload: {
|
|
468
|
+
recipient: to,
|
|
469
|
+
amount: BigInt(amount),
|
|
470
|
+
nonce: BigInt(nonce),
|
|
471
|
+
},
|
|
472
|
+
fee: 5000, // 5000 lamports fee
|
|
473
|
+
slot: await this.getSlot(),
|
|
474
|
+
timestamp: Date.now(),
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// Sign transaction (user provides signing function)
|
|
478
|
+
const signature = await signFn(tx, blockhash);
|
|
479
|
+
tx.signature = signature;
|
|
480
|
+
|
|
481
|
+
// Send to blockchain (real RPC call)
|
|
482
|
+
const receipt = await this.sendTransaction(tx);
|
|
483
|
+
return receipt;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Build and send a stake delegation transaction
|
|
488
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
489
|
+
*
|
|
490
|
+
* @param {Object} params
|
|
491
|
+
* @param {string} params.staker - Staker address (base58)
|
|
492
|
+
* @param {string} params.validator - Validator address (base58)
|
|
493
|
+
* @param {number} params.amount - Amount to stake in lamports
|
|
494
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
495
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
496
|
+
*/
|
|
497
|
+
async stake({ staker, validator, amount, signFn }) {
|
|
498
|
+
if (!staker || !validator || !amount === undefined) {
|
|
499
|
+
throw new Error('staker, validator, and amount are required');
|
|
500
|
+
}
|
|
501
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
502
|
+
throw new Error('signFn is required');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
506
|
+
|
|
507
|
+
const tx = {
|
|
508
|
+
signature: '',
|
|
509
|
+
signer: staker,
|
|
510
|
+
tx_type: 'Stake',
|
|
511
|
+
payload: {
|
|
512
|
+
validator: validator,
|
|
513
|
+
amount: BigInt(amount),
|
|
514
|
+
},
|
|
515
|
+
fee: 5000,
|
|
516
|
+
slot: await this.getSlot(),
|
|
517
|
+
timestamp: Date.now(),
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
const signature = await signFn(tx, blockhash);
|
|
521
|
+
tx.signature = signature;
|
|
522
|
+
|
|
523
|
+
const receipt = await this.sendTransaction(tx);
|
|
524
|
+
return receipt;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Build and send an unstake (withdraw) transaction
|
|
529
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
530
|
+
*
|
|
531
|
+
* @param {Object} params
|
|
532
|
+
* @param {string} params.stakeAccount - Stake account address (base58)
|
|
533
|
+
* @param {number} params.amount - Amount to unstake in lamports
|
|
534
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
535
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
536
|
+
*/
|
|
537
|
+
async unstake({ stakeAccount, amount, signFn }) {
|
|
538
|
+
if (!stakeAccount || !amount === undefined) {
|
|
539
|
+
throw new Error('stakeAccount and amount are required');
|
|
540
|
+
}
|
|
541
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
542
|
+
throw new Error('signFn is required');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
546
|
+
|
|
547
|
+
const tx = {
|
|
548
|
+
signature: '',
|
|
549
|
+
signer: stakeAccount,
|
|
550
|
+
tx_type: 'Unstake',
|
|
551
|
+
payload: {
|
|
552
|
+
stake_account: stakeAccount,
|
|
553
|
+
amount: BigInt(amount),
|
|
554
|
+
},
|
|
555
|
+
fee: 5000,
|
|
556
|
+
slot: await this.getSlot(),
|
|
557
|
+
timestamp: Date.now(),
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
const signature = await signFn(tx, blockhash);
|
|
561
|
+
tx.signature = signature;
|
|
562
|
+
|
|
563
|
+
const receipt = await this.sendTransaction(tx);
|
|
564
|
+
return receipt;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Build and send a claim rewards transaction
|
|
569
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
570
|
+
*
|
|
571
|
+
* @param {Object} params
|
|
572
|
+
* @param {string} params.stakeAccount - Stake account address (base58)
|
|
573
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
574
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
575
|
+
*/
|
|
576
|
+
async claimRewards({ stakeAccount, signFn }) {
|
|
577
|
+
if (!stakeAccount) {
|
|
578
|
+
throw new Error('stakeAccount is required');
|
|
579
|
+
}
|
|
580
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
581
|
+
throw new Error('signFn is required');
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
585
|
+
|
|
586
|
+
const tx = {
|
|
587
|
+
signature: '',
|
|
588
|
+
signer: stakeAccount,
|
|
589
|
+
tx_type: 'ClaimRewards',
|
|
590
|
+
payload: {
|
|
591
|
+
stake_account: stakeAccount,
|
|
592
|
+
},
|
|
593
|
+
fee: 5000,
|
|
594
|
+
slot: await this.getSlot(),
|
|
595
|
+
timestamp: Date.now(),
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const signature = await signFn(tx, blockhash);
|
|
599
|
+
tx.signature = signature;
|
|
600
|
+
|
|
601
|
+
const receipt = await this.sendTransaction(tx);
|
|
602
|
+
return receipt;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// ============================================================
|
|
606
|
+
// NFT Methods - Real blockchain calls for NFT operations
|
|
607
|
+
// ============================================================
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Create a new NFT
|
|
611
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
612
|
+
*
|
|
613
|
+
* @param {Object} params
|
|
614
|
+
* @param {string} params.creator - Creator address (base58)
|
|
615
|
+
* @param {string} params.metadataUrl - URL to NFT metadata (JSON)
|
|
616
|
+
* @param {number} params.royalties - Royalty basis points (e.g., 500 = 5%)
|
|
617
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
618
|
+
* @returns {Promise<Object>} Transaction receipt with NFT ID
|
|
619
|
+
*/
|
|
620
|
+
async createNFT({ creator, metadataUrl, royalties, signFn }) {
|
|
621
|
+
if (!creator || !metadataUrl || royalties === undefined) {
|
|
622
|
+
throw new Error('creator, metadataUrl, and royalties are required');
|
|
623
|
+
}
|
|
624
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
625
|
+
throw new Error('signFn is required');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
629
|
+
|
|
630
|
+
const tx = {
|
|
631
|
+
signature: '',
|
|
632
|
+
signer: creator,
|
|
633
|
+
tx_type: 'CreateNFT',
|
|
634
|
+
payload: {
|
|
635
|
+
metadata_url: metadataUrl,
|
|
636
|
+
royalties: royalties,
|
|
637
|
+
},
|
|
638
|
+
fee: 10000, // Higher fee for NFT creation
|
|
639
|
+
slot: await this.getSlot(),
|
|
640
|
+
timestamp: Date.now(),
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const signature = await signFn(tx, blockhash);
|
|
644
|
+
tx.signature = signature;
|
|
645
|
+
|
|
646
|
+
const receipt = await this.sendTransaction(tx);
|
|
647
|
+
return receipt;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Transfer an NFT to another address
|
|
652
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
653
|
+
*
|
|
654
|
+
* @param {Object} params
|
|
655
|
+
* @param {string} params.from - Current owner address (base58)
|
|
656
|
+
* @param {string} params.nftId - NFT ID
|
|
657
|
+
* @param {string} params.to - Recipient address (base58)
|
|
658
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
659
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
660
|
+
*/
|
|
661
|
+
async transferNFT({ from, nftId, to, signFn }) {
|
|
662
|
+
if (!from || !nftId || !to) {
|
|
663
|
+
throw new Error('from, nftId, and to are required');
|
|
664
|
+
}
|
|
665
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
666
|
+
throw new Error('signFn is required');
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
670
|
+
|
|
671
|
+
const tx = {
|
|
672
|
+
signature: '',
|
|
673
|
+
signer: from,
|
|
674
|
+
tx_type: 'TransferNFT',
|
|
675
|
+
payload: {
|
|
676
|
+
nft_id: nftId,
|
|
677
|
+
recipient: to,
|
|
678
|
+
},
|
|
679
|
+
fee: 5000,
|
|
680
|
+
slot: await this.getSlot(),
|
|
681
|
+
timestamp: Date.now(),
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
const signature = await signFn(tx, blockhash);
|
|
685
|
+
tx.signature = signature;
|
|
686
|
+
|
|
687
|
+
const receipt = await this.sendTransaction(tx);
|
|
688
|
+
return receipt;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Update NFT metadata URL
|
|
693
|
+
* Makes real RPC calls: getRecentBlockhash() + sendTransaction()
|
|
694
|
+
*
|
|
695
|
+
* @param {Object} params
|
|
696
|
+
* @param {string} params.creator - NFT creator/owner address (base58)
|
|
697
|
+
* @param {string} params.nftId - NFT ID
|
|
698
|
+
* @param {string} params.metadataUrl - New metadata URL
|
|
699
|
+
* @param {Function} params.signFn - Function to sign the transaction
|
|
700
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
701
|
+
*/
|
|
702
|
+
async updateMetadata({ creator, nftId, metadataUrl, signFn }) {
|
|
703
|
+
if (!creator || !nftId || !metadataUrl) {
|
|
704
|
+
throw new Error('creator, nftId, and metadataUrl are required');
|
|
705
|
+
}
|
|
706
|
+
if (!signFn || typeof signFn !== 'function') {
|
|
707
|
+
throw new Error('signFn is required');
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const { blockhash } = await this.getRecentBlockhash();
|
|
711
|
+
|
|
712
|
+
const tx = {
|
|
713
|
+
signature: '',
|
|
714
|
+
signer: creator,
|
|
715
|
+
tx_type: 'UpdateMetadata',
|
|
716
|
+
payload: {
|
|
717
|
+
nft_id: nftId,
|
|
718
|
+
metadata_url: metadataUrl,
|
|
719
|
+
},
|
|
720
|
+
fee: 5000,
|
|
721
|
+
slot: await this.getSlot(),
|
|
722
|
+
timestamp: Date.now(),
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
const signature = await signFn(tx, blockhash);
|
|
726
|
+
tx.signature = signature;
|
|
727
|
+
|
|
728
|
+
const receipt = await this.sendTransaction(tx);
|
|
729
|
+
return receipt;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// ============================================================
|
|
734
|
+
// Convenience Functions (for quick one-off calls)
|
|
735
|
+
// ============================================================
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Create a new AetherClient instance
|
|
739
|
+
* @param {Object} options - Client options
|
|
740
|
+
* @returns {AetherClient}
|
|
741
|
+
*/
|
|
742
|
+
function createClient(options = {}) {
|
|
743
|
+
return new AetherClient(options);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Quick slot check (uses default RPC)
|
|
748
|
+
* @returns {Promise<number>} Current slot
|
|
749
|
+
*/
|
|
750
|
+
async function getSlot() {
|
|
751
|
+
const client = new AetherClient();
|
|
752
|
+
return client.getSlot();
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Quick balance check (uses default RPC)
|
|
757
|
+
* @param {string} address - Account address
|
|
758
|
+
* @returns {Promise<number>} Balance in lamports
|
|
759
|
+
*/
|
|
760
|
+
async function getBalance(address) {
|
|
761
|
+
const client = new AetherClient();
|
|
762
|
+
return client.getBalance(address);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Quick health check (uses default RPC)
|
|
767
|
+
* @returns {Promise<string>} 'ok' if healthy
|
|
768
|
+
*/
|
|
769
|
+
async function getHealth() {
|
|
770
|
+
const client = new AetherClient();
|
|
771
|
+
return client.getHealth();
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Get current block height (uses default RPC)
|
|
776
|
+
* @returns {Promise<number>} Block height
|
|
777
|
+
*/
|
|
778
|
+
async function getBlockHeight() {
|
|
779
|
+
const client = new AetherClient();
|
|
780
|
+
return client.getBlockHeight();
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Get epoch info (uses default RPC)
|
|
785
|
+
* @returns {Promise<Object>} Epoch info
|
|
786
|
+
*/
|
|
787
|
+
async function getEpoch() {
|
|
788
|
+
const client = new AetherClient();
|
|
789
|
+
return client.getEpochInfo();
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Get TPS (uses default RPC)
|
|
794
|
+
* @returns {Promise<number>} Transactions per second
|
|
795
|
+
*/
|
|
796
|
+
async function getTPS() {
|
|
797
|
+
const client = new AetherClient();
|
|
798
|
+
return client.getTPS();
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Get supply info (uses default RPC)
|
|
803
|
+
* @returns {Promise<Object>} Supply info
|
|
804
|
+
*/
|
|
805
|
+
async function getSupply() {
|
|
806
|
+
const client = new AetherClient();
|
|
807
|
+
return client.getSupply();
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Get fees info (uses default RPC)
|
|
812
|
+
* @returns {Promise<Object>} Fee info
|
|
813
|
+
*/
|
|
814
|
+
async function getFees() {
|
|
815
|
+
const client = new AetherClient();
|
|
816
|
+
return client.getFees();
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Get validators list (uses default RPC)
|
|
821
|
+
* @returns {Promise<Array>} List of validators
|
|
822
|
+
*/
|
|
823
|
+
async function getValidators() {
|
|
824
|
+
const client = new AetherClient();
|
|
825
|
+
return client.getValidators();
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Get peers list (uses default RPC)
|
|
830
|
+
* @returns {Promise<Array>} List of peers
|
|
831
|
+
*/
|
|
832
|
+
async function getPeers() {
|
|
833
|
+
const client = new AetherClient();
|
|
834
|
+
return client.getClusterPeers();
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Get slot production stats (uses default RPC)
|
|
839
|
+
* @returns {Promise<Object>} Slot production stats
|
|
840
|
+
*/
|
|
841
|
+
async function getSlotProduction() {
|
|
842
|
+
const client = new AetherClient();
|
|
843
|
+
return client.getSlotProduction();
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Get account info (uses default RPC)
|
|
848
|
+
* @param {string} address - Account address
|
|
849
|
+
* @returns {Promise<Object>} Account info
|
|
850
|
+
*/
|
|
851
|
+
async function getAccount(address) {
|
|
852
|
+
const client = new AetherClient();
|
|
853
|
+
return client.getAccount(address);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Get stake positions (uses default RPC)
|
|
858
|
+
* @param {string} address - Account address
|
|
859
|
+
* @returns {Promise<Array>} Stake positions
|
|
860
|
+
*/
|
|
861
|
+
async function getStakePositions(address) {
|
|
862
|
+
const client = new AetherClient();
|
|
863
|
+
return client.getStakePositions(address);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* Get rewards info (uses default RPC)
|
|
868
|
+
* @param {string} address - Account address
|
|
869
|
+
* @returns {Promise<Object>} Rewards info
|
|
870
|
+
*/
|
|
871
|
+
async function getRewards(address) {
|
|
872
|
+
const client = new AetherClient();
|
|
873
|
+
return client.getRewards(address);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Get transaction by signature (uses default RPC)
|
|
878
|
+
* @param {string} signature - Transaction signature
|
|
879
|
+
* @returns {Promise<Object>} Transaction info
|
|
880
|
+
*/
|
|
881
|
+
async function getTransaction(signature) {
|
|
882
|
+
const client = new AetherClient();
|
|
883
|
+
return client.getTransaction(signature);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Get recent transactions (uses default RPC)
|
|
888
|
+
* @param {string} address - Account address
|
|
889
|
+
* @param {number} limit - Max transactions
|
|
890
|
+
* @returns {Promise<Array>} Recent transactions
|
|
891
|
+
*/
|
|
892
|
+
async function getRecentTransactions(address, limit = 20) {
|
|
893
|
+
const client = new AetherClient();
|
|
894
|
+
return client.getRecentTransactions(address, limit);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* Get transaction history with signatures for an address (uses default RPC)
|
|
899
|
+
* @param {string} address - Account address
|
|
900
|
+
* @param {number} limit - Max transactions
|
|
901
|
+
* @returns {Promise<Object>} Transaction history with signatures and details
|
|
902
|
+
*/
|
|
903
|
+
async function getTransactionHistory(address, limit = 20) {
|
|
904
|
+
const client = new AetherClient();
|
|
905
|
+
return client.getTransactionHistory(address, limit);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* Get all SPL token accounts for a wallet (uses default RPC)
|
|
910
|
+
* @param {string} address - Account address
|
|
911
|
+
* @returns {Promise<Array>} Token accounts with mint, amount, decimals
|
|
912
|
+
*/
|
|
913
|
+
async function getTokenAccounts(address) {
|
|
914
|
+
const client = new AetherClient();
|
|
915
|
+
return client.getTokenAccounts(address);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Get all stake accounts for a wallet (uses default RPC)
|
|
920
|
+
* @param {string} address - Account address
|
|
921
|
+
* @returns {Promise<Array>} Stake accounts list
|
|
922
|
+
*/
|
|
923
|
+
async function getStakeAccounts(address) {
|
|
924
|
+
const client = new AetherClient();
|
|
925
|
+
return client.getStakeAccounts(address);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Get validator APY (uses default RPC)
|
|
930
|
+
* @param {string} validatorAddr - Validator address
|
|
931
|
+
* @returns {Promise<Object>} APY info
|
|
932
|
+
*/
|
|
933
|
+
async function getValidatorAPY(validatorAddr) {
|
|
934
|
+
const client = new AetherClient();
|
|
935
|
+
return client.getValidatorAPY(validatorAddr);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Send transaction (uses default RPC)
|
|
940
|
+
* @param {Object} tx - Signed transaction
|
|
941
|
+
* @returns {Promise<Object>} Transaction receipt
|
|
942
|
+
*/
|
|
943
|
+
async function sendTransaction(tx) {
|
|
944
|
+
const client = new AetherClient();
|
|
945
|
+
return client.sendTransaction(tx);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Ping RPC endpoint
|
|
950
|
+
* @param {string} rpcUrl - RPC URL to ping
|
|
951
|
+
* @returns {Promise<Object>} Ping result with latency
|
|
952
|
+
*/
|
|
953
|
+
async function ping(rpcUrl) {
|
|
954
|
+
const client = new AetherClient({ rpcUrl });
|
|
955
|
+
const start = Date.now();
|
|
956
|
+
try {
|
|
957
|
+
await client.getSlot();
|
|
958
|
+
return { ok: true, latency: Date.now() - start, rpc: rpcUrl || DEFAULT_RPC_URL };
|
|
959
|
+
} catch (err) {
|
|
960
|
+
return { ok: false, error: err.message, rpc: rpcUrl || DEFAULT_RPC_URL };
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Low-level RPC helpers (from rpc.js)
|
|
965
|
+
const { rpcGet, rpcPost } = require('./rpc');
|
|
966
|
+
|
|
967
|
+
// ============================================================
|
|
968
|
+
// Exports
|
|
969
|
+
// ============================================================
|
|
970
|
+
|
|
971
|
+
module.exports = {
|
|
972
|
+
// Main class
|
|
973
|
+
AetherClient,
|
|
974
|
+
|
|
975
|
+
// Factory function
|
|
976
|
+
createClient,
|
|
977
|
+
|
|
978
|
+
// Convenience functions (all chain queries)
|
|
979
|
+
getSlot,
|
|
980
|
+
getBlockHeight,
|
|
981
|
+
getEpoch,
|
|
982
|
+
getAccount,
|
|
983
|
+
getBalance,
|
|
984
|
+
getTransaction,
|
|
985
|
+
getRecentTransactions,
|
|
986
|
+
getTransactionHistory,
|
|
987
|
+
getTokenAccounts,
|
|
988
|
+
getStakeAccounts,
|
|
989
|
+
getValidators,
|
|
990
|
+
getTPS,
|
|
991
|
+
getSupply,
|
|
992
|
+
getSlotProduction,
|
|
993
|
+
getFees,
|
|
994
|
+
getStakePositions,
|
|
995
|
+
getRewards,
|
|
996
|
+
getValidatorAPY,
|
|
997
|
+
getPeers,
|
|
998
|
+
getHealth,
|
|
999
|
+
|
|
1000
|
+
// Transactions
|
|
1001
|
+
sendTransaction,
|
|
1002
|
+
|
|
1003
|
+
// Utilities
|
|
1004
|
+
ping,
|
|
1005
|
+
|
|
1006
|
+
// Low-level RPC
|
|
1007
|
+
rpcGet,
|
|
1008
|
+
rpcPost,
|
|
1009
|
+
|
|
1010
|
+
// Constants
|
|
1011
|
+
DEFAULT_RPC_URL,
|
|
1012
|
+
DEFAULT_TIMEOUT_MS,
|
|
1013
|
+
};
|