aether-hub 1.2.6 → 1.2.8

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.
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aether-cli claim
4
+ *
5
+ * Claim accumulated staking rewards for a wallet.
6
+ * Fetches pending rewards from the chain and submits a claim transaction.
7
+ *
8
+ * Usage:
9
+ * aether claim --address <addr> [--json] [--rpc <url>]
10
+ *
11
+ * Examples:
12
+ * aether claim --address ATHxxx
13
+ * aether claim --address ATHxxx --json
14
+ */
15
+
16
+ const https = require('https');
17
+ const http = require('http');
18
+
19
+ // ANSI colours
20
+ const C = {
21
+ reset: '\x1b[0m',
22
+ bright: '\x1b[1m',
23
+ dim: '\x1b[2m',
24
+ red: '\x1b[31m',
25
+ green: '\x1b[32m',
26
+ yellow: '\x1b[33m',
27
+ cyan: '\x1b[36m',
28
+ magenta: '\x1b[35m',
29
+ };
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Config
33
+ // ---------------------------------------------------------------------------
34
+
35
+ function getDefaultRpc() {
36
+ return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // HTTP helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ function httpRequest(rpcUrl, pathStr, options = {}, timeoutMs = 8000) {
44
+ return new Promise((resolve, reject) => {
45
+ const url = new URL(pathStr, rpcUrl);
46
+ const lib = url.protocol === 'https:' ? https : http;
47
+ const reqOptions = {
48
+ hostname: url.hostname,
49
+ port: url.port || (url.protocol === 'https:' ? 443 : 80),
50
+ path: url.pathname + url.search,
51
+ method: options.method || 'GET',
52
+ headers: { 'Content-Type': 'application/json', ...options.headers },
53
+ };
54
+ const req = lib.request(reqOptions, (res) => {
55
+ let data = '';
56
+ res.on('data', (chunk) => data += chunk);
57
+ res.on('end', () => {
58
+ try { resolve(JSON.parse(data)); }
59
+ catch { resolve(data); }
60
+ });
61
+ });
62
+ req.on('error', reject);
63
+ req.setTimeout(timeoutMs, () => {
64
+ req.destroy();
65
+ reject(new Error(`Request timeout after ${timeoutMs}ms`));
66
+ });
67
+ if (options.body) req.write(options.body);
68
+ req.end();
69
+ });
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Argument parsing
74
+ // ---------------------------------------------------------------------------
75
+
76
+ function parseArgs() {
77
+ const args = process.argv.slice(2);
78
+ const result = { address: null, json: false };
79
+
80
+ for (let i = 0; i < args.length; i++) {
81
+ if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) {
82
+ result.address = args[i + 1];
83
+ i++;
84
+ } else if (args[i] === '--json' || args[i] === '--json-output') {
85
+ result.json = true;
86
+ } else if (args[i] === '--rpc' && args[i + 1]) {
87
+ result.rpc = args[i + 1];
88
+ i++;
89
+ } else if (args[i] === '--help' || args[i] === '-h') {
90
+ result.help = true;
91
+ } else if (args[i] === '--dry-run') {
92
+ result.dryRun = true;
93
+ }
94
+ }
95
+
96
+ return result;
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Format helpers
101
+ // ---------------------------------------------------------------------------
102
+
103
+ function formatAether(lamports) {
104
+ const aeth = (lamports || 0) / 1e9;
105
+ return aeth.toLocaleString(undefined, { minimumFractionDigits: 4, maximumFractionDigits: 4 }) + ' AETH';
106
+ }
107
+
108
+ function formatFlux(lamports) {
109
+ const flux = (lamports || 0) / 1e6;
110
+ return flux.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' FLUX';
111
+ }
112
+
113
+ function shortPubkey(pubkey) {
114
+ if (!pubkey || pubkey.length < 16) return pubkey || 'unknown';
115
+ return pubkey.slice(0, 8) + '...' + pubkey.slice(-8);
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Main
120
+ // ---------------------------------------------------------------------------
121
+
122
+ async function claimCommand() {
123
+ const opts = parseArgs();
124
+
125
+ if (opts.help) {
126
+ console.log(`
127
+ ${C.bright}${C.cyan}claim${C.reset} — Claim accumulated staking rewards for a wallet
128
+
129
+ ${C.bright}USAGE${C.reset}
130
+ aether claim --address <addr> [--json] [--rpc <url>] [--dry-run]
131
+
132
+ ${C.bright}OPTIONS${C.reset}
133
+ --address <addr> Wallet address (ATH...)
134
+ --json Output raw JSON
135
+ --rpc <url> RPC endpoint (default: AETHER_RPC or localhost:8899)
136
+ --dry-run Preview claim without submitting transaction
137
+ --help Show this help
138
+
139
+ ${C.bright}EXAMPLES${C.reset}
140
+ aether claim --address ATH3abc...
141
+ aether claim --address ATH3abc... --dry-run
142
+ aether claim --address ATH3abc... --json
143
+ `);
144
+ return;
145
+ }
146
+
147
+ if (!opts.address) {
148
+ console.log(` ${C.red}✗ Missing --address${C.reset}\n`);
149
+ console.log(` Usage: aether claim --address <addr> [--json] [--dry-run]\n`);
150
+ return;
151
+ }
152
+
153
+ const rpcUrl = opts.rpc || getDefaultRpc();
154
+ const address = opts.address;
155
+ const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
156
+
157
+ if (!opts.json) {
158
+ console.log(`\n${C.bright}${C.cyan}── Claim Staking Rewards ────────────────────────────────${C.reset}\n`);
159
+ console.log(` ${C.dim}Wallet:${C.reset} ${address}`);
160
+ console.log(` ${C.dim}RPC: ${C.reset} ${rpcUrl}`);
161
+ if (opts.dryRun) console.log(` ${C.yellow}(dry-run mode - no transaction will be submitted)${C.reset}`);
162
+ console.log();
163
+ }
164
+
165
+ try {
166
+ // Step 1: Fetch stake positions to calculate pending rewards
167
+ const stakeRes = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(rawAddr)}`);
168
+
169
+ let stakeAccounts = [];
170
+ if (Array.isArray(stakeRes)) {
171
+ stakeAccounts = stakeRes;
172
+ } else if (stakeRes && typeof stakeRes === 'object') {
173
+ stakeAccounts = stakeRes.accounts || stakeRes.stake_accounts || stakeRes.data || [];
174
+ }
175
+
176
+ if (!opts.json) {
177
+ console.log(` ${C.dim}Fetching stake positions...${C.reset}`);
178
+ }
179
+
180
+ if (!stakeAccounts || stakeAccounts.length === 0) {
181
+ console.log(` ${C.yellow}? No active stake positions found.${C.reset}`);
182
+ console.log(` ${C.dim} Stake AETH with: ${C.cyan}aether stake --validator <addr> --amount <aeth>${C.reset}\n`);
183
+ return;
184
+ }
185
+
186
+ // Calculate total pending rewards
187
+ let totalPendingRewards = 0;
188
+ const rewardBreakdown = [];
189
+
190
+ for (const acc of stakeAccounts) {
191
+ const pendingRewards = acc.pending_rewards || acc.pendingRewards || acc.rewards || 0;
192
+ const stakeLamports = acc.stake_lamports || acc.lamports || 0;
193
+ const validator = acc.validator || acc.delegate || acc.validator_address || 'unknown';
194
+
195
+ totalPendingRewards += pendingRewards;
196
+ rewardBreakdown.push({
197
+ stakeAcct: acc.pubkey || acc.publicKey || acc.account || 'unknown',
198
+ validator,
199
+ stakeLamports,
200
+ pendingRewards,
201
+ });
202
+ }
203
+
204
+ if (!opts.json) {
205
+ console.log(` ${C.bright}Stake Positions (${stakeAccounts.length})${C.reset}\n`);
206
+
207
+ for (const pos of rewardBreakdown) {
208
+ const shortVal = shortPubkey(pos.validator);
209
+ const shortAcct = shortPubkey(pos.stakeAcct);
210
+ console.log(` ${C.dim}├─ ${C.reset}${shortAcct} → ${C.cyan}${shortVal}${C.reset}`);
211
+ console.log(` │ ${C.dim}Staked:${C.reset} ${formatAether(pos.stakeLamports)}`);
212
+ console.log(` │ ${C.green}Pending:${C.reset} ${formatFlux(pos.pendingRewards)}\n`);
213
+ }
214
+
215
+ console.log(` ${C.dim}────────────────────────────────────────${C.reset}`);
216
+ console.log(` ${C.bright}Total Pending Rewards:${C.reset} ${C.green}${formatFlux(totalPendingRewards)}${C.reset}\n`);
217
+ }
218
+
219
+ // Step 2: If not dry-run, submit claim transaction
220
+ if (opts.dryRun) {
221
+ console.log(` ${C.yellow}⚠ Dry run - not submitting claim transaction${C.reset}\n`);
222
+ if (opts.json) {
223
+ console.log(JSON.stringify({
224
+ wallet_address: address,
225
+ dry_run: true,
226
+ stake_count: stakeAccounts.length,
227
+ total_pending_flux: totalPendingRewards,
228
+ total_pending_aeth: (totalPendingRewards / 1e6).toFixed(2),
229
+ breakdown: rewardBreakdown.map(r => ({
230
+ stake_account: r.stakeAcct,
231
+ validator: r.validator,
232
+ pending_flux: r.pendingRewards,
233
+ })),
234
+ }, null, 2));
235
+ }
236
+ return;
237
+ }
238
+
239
+ // Step 3: Submit claim transaction
240
+ if (!opts.json) {
241
+ console.log(` ${C.dim}Submitting claim transaction...${C.reset}`);
242
+ }
243
+
244
+ const claimBody = JSON.stringify({
245
+ address: rawAddr,
246
+ stake_accounts: rewardBreakdown.map(r => r.stakeAcct),
247
+ });
248
+
249
+ const claimRes = await httpRequest(rpcUrl, '/v1/claim', {
250
+ method: 'POST',
251
+ body: claimBody,
252
+ });
253
+
254
+ if (opts.json) {
255
+ console.log(JSON.stringify({
256
+ wallet_address: address,
257
+ success: !claimRes.error,
258
+ total_claimed_flux: claimRes.claimed || totalPendingRewards,
259
+ tx_signature: claimRes.signature || claimRes.txid || null,
260
+ block_height: claimRes.block_height || null,
261
+ claimed_at: new Date().toISOString(),
262
+ }, null, 2));
263
+ return;
264
+ }
265
+
266
+ if (claimRes.error) {
267
+ console.log(` ${C.red}✗ Claim failed:${C.reset} ${claimRes.error}\n`);
268
+ process.exit(1);
269
+ }
270
+
271
+ console.log(` ${C.green}✓ Rewards claimed!${C.reset}`);
272
+ console.log(` ${C.dim} Amount:${C.reset} ${C.green}${formatFlux(claimRes.claimed || totalPendingRewards)}${C.reset}`);
273
+ if (claimRes.signature || claimRes.txid) {
274
+ console.log(` ${C.dim} Tx:${C.reset} ${shortPubkey(claimRes.signature || claimRes.txid)}`);
275
+ }
276
+ console.log();
277
+
278
+ } catch (err) {
279
+ if (opts.json) {
280
+ console.log(JSON.stringify({ address, error: err.message }, null, 2));
281
+ } else {
282
+ console.log(` ${C.red}✗ Failed to claim rewards:${C.reset} ${err.message}\n`);
283
+ }
284
+ process.exit(1);
285
+ }
286
+ }
287
+
288
+ module.exports = { claimCommand };
289
+
290
+ if (require.main === module) {
291
+ claimCommand();
292
+ }
@@ -9,10 +9,11 @@
9
9
  * aether delegations list --address <addr> List all stake delegations
10
10
  * aether delegations list --address <addr> --json JSON output
11
11
  * aether delegations claim --address <addr> --account <stakeAcct> [--json]
12
+ *
13
+ * SDK wired to: GET /v1/slot, GET /v1/account/<addr>, GET /v1/stake/<addr>
12
14
  */
13
15
 
14
- const http = require('http');
15
- const https = require('https');
16
+ const path = require('path');
16
17
  const readline = require('readline');
17
18
  const crypto = require('crypto');
18
19
  const bs58 = require('bs58').default;
@@ -32,18 +33,25 @@ const C = {
32
33
  };
33
34
 
34
35
  const DERIVATION_PATH = "m/44'/7777777'/0'/0'";
35
- const CLI_VERSION = '1.0.5';
36
+ const CLI_VERSION = '1.0.6';
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // SDK Import
40
+ // ---------------------------------------------------------------------------
41
+
42
+ const sdkPath = path.join(__dirname, '..', 'sdk', 'index.js');
43
+ const aether = require(sdkPath);
36
44
 
37
45
  // ---------------------------------------------------------------------------
38
46
  // Paths & config
39
47
  // ---------------------------------------------------------------------------
40
48
 
41
49
  function getAetherDir() {
42
- return require('path').join(require('os').homedir(), '.aether');
50
+ return path.join(require('os').homedir(), '.aether');
43
51
  }
44
52
 
45
53
  function loadConfig() {
46
- const p = require('path').join(getAetherDir(), 'config.json');
54
+ const p = path.join(getAetherDir(), 'config.json');
47
55
  if (!require('fs').existsSync(p)) return { defaultWallet: null };
48
56
  try {
49
57
  return JSON.parse(require('fs').readFileSync(p, 'utf8'));
@@ -53,7 +61,7 @@ function loadConfig() {
53
61
  }
54
62
 
55
63
  function loadWallet(address) {
56
- const fp = require('path').join(getAetherDir(), 'wallets', `${address}.json`);
64
+ const fp = path.join(getAetherDir(), 'wallets', `${address}.json`);
57
65
  if (!require('fs').existsSync(fp)) return null;
58
66
  return JSON.parse(require('fs').readFileSync(fp, 'utf8'));
59
67
  }
@@ -75,57 +83,15 @@ function formatAddress(publicKey) {
75
83
  }
76
84
 
77
85
  // ---------------------------------------------------------------------------
78
- // HTTP helpers
86
+ // Config helpers
79
87
  // ---------------------------------------------------------------------------
80
88
 
81
- function httpRequest(rpcUrl, path) {
82
- return new Promise((resolve, reject) => {
83
- const url = new URL(path, rpcUrl);
84
- const lib = url.protocol === 'https:' ? https : http;
85
- const req = lib.request({
86
- hostname: url.hostname,
87
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
88
- path: url.pathname + url.search,
89
- method: 'GET',
90
- timeout: 8000,
91
- headers: { 'Content-Type': 'application/json' },
92
- }, (res) => {
93
- let data = '';
94
- res.on('data', (chunk) => data += chunk);
95
- res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); } });
96
- });
97
- req.on('error', reject);
98
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
99
- req.end();
100
- });
101
- }
102
-
103
- function httpPost(rpcUrl, path, body) {
104
- return new Promise((resolve, reject) => {
105
- const url = new URL(path, rpcUrl);
106
- const lib = url.protocol === 'https:' ? https : http;
107
- const bodyStr = JSON.stringify(body);
108
- const req = lib.request({
109
- hostname: url.hostname,
110
- port: url.port || (url.protocol === 'https:' ? 443 : 80),
111
- path: url.pathname + url.search,
112
- method: 'POST',
113
- timeout: 8000,
114
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(bodyStr) },
115
- }, (res) => {
116
- let data = '';
117
- res.on('data', (chunk) => data += chunk);
118
- res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve({ raw: data }); } });
119
- });
120
- req.on('error', reject);
121
- req.on('timeout', () => { req.destroy(); reject(new Error('Request timeout')); });
122
- req.write(bodyStr);
123
- req.end();
124
- });
89
+ function getDefaultRpc() {
90
+ return process.env.AETHER_RPC || aether.DEFAULT_RPC_URL || 'http://127.0.0.1:8899';
125
91
  }
126
92
 
127
- function getDefaultRpc() {
128
- return process.env.AETHER_RPC || 'http://127.0.0.1:8899';
93
+ function createClient(rpcUrl) {
94
+ return new aether.AetherClient({ rpcUrl });
129
95
  }
130
96
 
131
97
  function formatAether(lamports) {
@@ -159,7 +125,7 @@ async function askMnemonic(rl, prompt) {
159
125
  }
160
126
 
161
127
  // ---------------------------------------------------------------------------
162
- // LIST DELEGATIONS
128
+ // LIST DELEGATIONS — uses SDK
163
129
  // ---------------------------------------------------------------------------
164
130
 
165
131
  async function listDelegations(args) {
@@ -169,9 +135,9 @@ async function listDelegations(args) {
169
135
  let rpcUrl = getDefaultRpc();
170
136
 
171
137
  for (let i = 0; i < args.length; i++) {
172
- if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[i + 1];
138
+ if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[++i];
173
139
  else if (args[i] === '--json' || args[i] === '-j') asJson = true;
174
- else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[i + 1];
140
+ else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[++i];
175
141
  }
176
142
 
177
143
  if (!address) {
@@ -186,29 +152,15 @@ async function listDelegations(args) {
186
152
  return;
187
153
  }
188
154
 
189
- try {
190
- const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
191
-
192
- // Fetch account info for context
193
- const account = await httpRequest(rpcUrl, `/v1/account/${rawAddr}`);
155
+ const client = createClient(rpcUrl);
156
+ const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
194
157
 
195
- // Fetch stake accounts for this wallet
196
- // The RPC may return stake accounts via a dedicated endpoint or as program accounts
197
- let stakeAccounts = [];
198
- try {
199
- const res = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(rawAddr)}`);
200
- if (res && !res.error) {
201
- stakeAccounts = Array.isArray(res) ? res : (res.accounts || []);
202
- }
203
- } catch {
204
- // Fallback: try program account query
205
- try {
206
- const res2 = await httpRequest(rpcUrl, `/v1/program/STAKE/accounts?owner=${encodeURIComponent(rawAddr)}`);
207
- if (res2 && !res2.error) {
208
- stakeAccounts = Array.isArray(res2) ? res2 : (res2.accounts || []);
209
- }
210
- } catch { /* no stake accounts or RPC doesn't support this endpoint */ }
211
- }
158
+ try {
159
+ // Real chain RPC calls via SDK
160
+ const [account, stakeAccounts] = await Promise.all([
161
+ client.getAccountInfo(rawAddr).catch(() => null),
162
+ client.getStakePositions(rawAddr).catch(() => []),
163
+ ]);
212
164
 
213
165
  if (asJson) {
214
166
  console.log(JSON.stringify({
@@ -216,6 +168,7 @@ async function listDelegations(args) {
216
168
  rpc: rpcUrl,
217
169
  account: account && !account.error ? { lamports: account.lamports } : null,
218
170
  delegations: stakeAccounts,
171
+ cli_version: CLI_VERSION,
219
172
  fetched_at: new Date().toISOString(),
220
173
  }, null, 2));
221
174
  rl.close();
@@ -230,7 +183,7 @@ async function listDelegations(args) {
230
183
  }
231
184
  console.log();
232
185
 
233
- if (stakeAccounts.length === 0) {
186
+ if (!stakeAccounts || stakeAccounts.length === 0) {
234
187
  console.log(` ${C.dim}No stake delegations found for this wallet.${C.reset}`);
235
188
  console.log(` ${C.dim}Delegate with:${C.reset} ${C.cyan}aether stake --address ${address} --validator <val> --amount <aeth>${C.reset}\n`);
236
189
  rl.close();
@@ -282,7 +235,7 @@ async function listDelegations(args) {
282
235
  }
283
236
 
284
237
  // ---------------------------------------------------------------------------
285
- // CLAIM REWARDS
238
+ // CLAIM REWARDS — uses SDK for fetch, wallet for signing
286
239
  // ---------------------------------------------------------------------------
287
240
 
288
241
  async function claimRewards(args) {
@@ -294,10 +247,10 @@ async function claimRewards(args) {
294
247
  let rpcUrl = getDefaultRpc();
295
248
 
296
249
  for (let i = 0; i < args.length; i++) {
297
- if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[i + 1];
298
- else if ((args[i] === '--account' || args[i] === '-s') && args[i + 1]) stakeAccount = args[i + 1];
250
+ if ((args[i] === '--address' || args[i] === '-a') && args[i + 1]) address = args[++i];
251
+ else if ((args[i] === '--account' || args[i] === '-s') && args[i + 1]) stakeAccount = args[++i];
299
252
  else if (args[i] === '--json' || args[i] === '-j') asJson = true;
300
- else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[i + 1];
253
+ else if ((args[i] === '--rpc' || args[i] === '-r') && args[i + 1]) rpcUrl = args[++i];
301
254
  }
302
255
 
303
256
  if (!address) {
@@ -312,17 +265,14 @@ async function claimRewards(args) {
312
265
  return;
313
266
  }
314
267
 
268
+ const client = createClient(rpcUrl);
269
+
270
+ // If no stake account specified, fetch list via SDK
315
271
  if (!stakeAccount) {
316
- // Fetch list first to let user pick
317
- let stakeAccounts = [];
318
- try {
319
- const res = await httpRequest(rpcUrl, `/v1/stake?address=${encodeURIComponent(address.startsWith('ATH') ? address.slice(3) : address)}`);
320
- if (res && !res.error) {
321
- stakeAccounts = Array.isArray(res) ? res : (res.accounts || []);
322
- }
323
- } catch { /* noop */ }
272
+ const rawAddr = address.startsWith('ATH') ? address.slice(3) : address;
273
+ let stakeAccounts = await client.getStakePositions(rawAddr).catch(() => []);
324
274
 
325
- if (stakeAccounts.length === 0) {
275
+ if (!stakeAccounts || stakeAccounts.length === 0) {
326
276
  console.log(` ${C.red}✗ No stake accounts found.${C.reset} Use ${C.cyan}--account <stakeAcct>${C.reset} to specify one.\n`);
327
277
  rl.close();
328
278
  return;
@@ -366,7 +316,7 @@ async function claimRewards(args) {
366
316
 
367
317
  let keyPair;
368
318
  try {
369
- keyPair = deriveKeypair(mnemonic, DERIVATION_PATH);
319
+ keyPair = deriveKeypair(mnemonic);
370
320
  } catch (e) {
371
321
  console.log(` ${C.red}✗ Failed to derive keypair: ${e.message}${C.reset}\n`);
372
322
  rl.close();
@@ -404,10 +354,10 @@ async function claimRewards(args) {
404
354
  timestamp: Math.floor(Date.now() / 1000),
405
355
  };
406
356
 
407
- console.log(` ${C.dim}Submitting to ${rpcUrl}...${C.reset}`);
357
+ console.log(` ${C.dim}Submitting via SDK to ${rpcUrl}...${C.reset}`);
408
358
 
409
359
  try {
410
- const result = await httpPost(rpcUrl, '/v1/tx', tx);
360
+ const result = await client.sendTransaction(tx);
411
361
 
412
362
  if (result.error) {
413
363
  console.log(`\n ${C.red}✗ Claim failed:${C.reset} ${result.error}\n`);