@chainstream-io/cli 0.0.17 → 0.0.19
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/dist/index.js +402 -293
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -84,19 +84,8 @@ var init_config = __esm({
|
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
// src/wallet/types.ts
|
|
88
|
-
function toSdkChain(chain) {
|
|
89
|
-
return isSolanaChain(chain) ? "solana" : "evm";
|
|
90
|
-
}
|
|
91
|
-
var init_types = __esm({
|
|
92
|
-
"src/wallet/types.ts"() {
|
|
93
|
-
"use strict";
|
|
94
|
-
init_config();
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
87
|
// src/wallet/raw-wallet.ts
|
|
99
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
88
|
+
import { privateKeyToAccount, signTypedData as viemSignTypedData } from "viem/accounts";
|
|
100
89
|
import { Keypair, VersionedTransaction } from "@solana/web3.js";
|
|
101
90
|
import { sign as ed25519Sign } from "crypto";
|
|
102
91
|
function bs58Decode(str) {
|
|
@@ -122,37 +111,64 @@ function bs58Decode(str) {
|
|
|
122
111
|
}
|
|
123
112
|
return new Uint8Array(result.reverse());
|
|
124
113
|
}
|
|
125
|
-
|
|
114
|
+
function toHexKey(key) {
|
|
115
|
+
return key.startsWith("0x") ? key : `0x${key}`;
|
|
116
|
+
}
|
|
117
|
+
function createRawKeyWallet(key, chain) {
|
|
118
|
+
return isEvmChain(chain) ? new RawEvmWallet(key, chain) : new RawSvmWallet(key, chain);
|
|
119
|
+
}
|
|
120
|
+
var RawEvmWallet, RawSvmWallet;
|
|
126
121
|
var init_raw_wallet = __esm({
|
|
127
122
|
"src/wallet/raw-wallet.ts"() {
|
|
128
123
|
"use strict";
|
|
129
|
-
init_types();
|
|
130
124
|
init_config();
|
|
131
|
-
|
|
132
|
-
chain;
|
|
125
|
+
RawEvmWallet = class {
|
|
126
|
+
chain = "evm";
|
|
133
127
|
paymentChain;
|
|
134
128
|
address;
|
|
135
129
|
privateKey;
|
|
136
130
|
constructor(key, chain) {
|
|
137
131
|
this.paymentChain = chain;
|
|
138
|
-
this.chain = toSdkChain(chain);
|
|
139
132
|
this.privateKey = key;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
const account = privateKeyToAccount(toHexKey(key));
|
|
134
|
+
this.address = account.address;
|
|
135
|
+
}
|
|
136
|
+
async signMessage(message) {
|
|
137
|
+
const account = privateKeyToAccount(toHexKey(this.privateKey));
|
|
138
|
+
return account.signMessage({ message });
|
|
139
|
+
}
|
|
140
|
+
async signTransaction(serializedTx) {
|
|
141
|
+
const txBytes = Buffer.from(serializedTx, "base64");
|
|
142
|
+
const account = privateKeyToAccount(toHexKey(this.privateKey));
|
|
143
|
+
const signedHex = await account.signTransaction({ type: "legacy" });
|
|
144
|
+
return Buffer.from(signedHex.slice(2), "hex").toString("base64");
|
|
145
|
+
}
|
|
146
|
+
async signTypedData(typedData) {
|
|
147
|
+
return viemSignTypedData({
|
|
148
|
+
privateKey: toHexKey(this.privateKey),
|
|
149
|
+
...typedData,
|
|
150
|
+
domain: typedData.domain,
|
|
151
|
+
types: typedData.types
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async signRawHash(hash) {
|
|
155
|
+
const account = privateKeyToAccount(toHexKey(this.privateKey));
|
|
156
|
+
return account.sign({ hash });
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
RawSvmWallet = class {
|
|
160
|
+
chain = "solana";
|
|
161
|
+
paymentChain;
|
|
162
|
+
address;
|
|
163
|
+
privateKey;
|
|
164
|
+
constructor(key, chain) {
|
|
165
|
+
this.paymentChain = chain;
|
|
166
|
+
this.privateKey = key;
|
|
167
|
+
const decoded = bs58Decode(key);
|
|
168
|
+
const keypair = Keypair.fromSecretKey(decoded);
|
|
169
|
+
this.address = keypair.publicKey.toBase58();
|
|
149
170
|
}
|
|
150
171
|
async signMessage(message) {
|
|
151
|
-
if (isEvmChain(this.paymentChain)) {
|
|
152
|
-
const hex = this.privateKey.startsWith("0x") ? this.privateKey : `0x${this.privateKey}`;
|
|
153
|
-
const account = privateKeyToAccount(hex);
|
|
154
|
-
return account.signMessage({ message });
|
|
155
|
-
}
|
|
156
172
|
const decoded = bs58Decode(this.privateKey);
|
|
157
173
|
const secretKeyRaw = decoded.slice(0, 32);
|
|
158
174
|
const pkcs8Prefix = Buffer.from("302e020100300506032b657004220420", "hex");
|
|
@@ -163,17 +179,11 @@ var init_raw_wallet = __esm({
|
|
|
163
179
|
}
|
|
164
180
|
async signTransaction(serializedTx) {
|
|
165
181
|
const txBytes = Buffer.from(serializedTx, "base64");
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return Buffer.from(tx.serialize()).toString("base64");
|
|
172
|
-
}
|
|
173
|
-
const hex = this.privateKey.startsWith("0x") ? this.privateKey : `0x${this.privateKey}`;
|
|
174
|
-
const account = privateKeyToAccount(hex);
|
|
175
|
-
const signedHex = await account.signTransaction({ type: "legacy" });
|
|
176
|
-
return Buffer.from(signedHex.slice(2), "hex").toString("base64");
|
|
182
|
+
const tx = VersionedTransaction.deserialize(new Uint8Array(txBytes));
|
|
183
|
+
const decoded = bs58Decode(this.privateKey);
|
|
184
|
+
const keypair = Keypair.fromSecretKey(decoded);
|
|
185
|
+
tx.sign([keypair]);
|
|
186
|
+
return Buffer.from(tx.serialize()).toString("base64");
|
|
177
187
|
}
|
|
178
188
|
};
|
|
179
189
|
}
|
|
@@ -328,74 +338,131 @@ var init_turnkey = __esm({
|
|
|
328
338
|
});
|
|
329
339
|
|
|
330
340
|
// src/wallet/turnkey-wallet.ts
|
|
331
|
-
|
|
341
|
+
import { hashTypedData } from "viem";
|
|
342
|
+
async function turnkeySignRawPayload(creds, address, payloadHex, hashFunction) {
|
|
343
|
+
const result = await turnkeyRequest(
|
|
344
|
+
"/public/v1/submit/sign_raw_payload",
|
|
345
|
+
{
|
|
346
|
+
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
347
|
+
timestampMs: Date.now().toString(),
|
|
348
|
+
organizationId: creds.organizationId,
|
|
349
|
+
parameters: {
|
|
350
|
+
signWith: address,
|
|
351
|
+
payload: payloadHex,
|
|
352
|
+
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
353
|
+
hashFunction
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
creds
|
|
357
|
+
);
|
|
358
|
+
const sig = result.activity?.result?.signRawPayloadResult;
|
|
359
|
+
if (!sig) throw new Error("Turnkey sign: no signature in response");
|
|
360
|
+
return sig;
|
|
361
|
+
}
|
|
362
|
+
function formatEvmSignature(sig) {
|
|
363
|
+
const v = sig.v === "00" ? "1b" : "1c";
|
|
364
|
+
return `0x${sig.r}${sig.s}${v}`;
|
|
365
|
+
}
|
|
366
|
+
async function createTurnkeyWallets(creds) {
|
|
367
|
+
const [evmAddr, solAddr] = await Promise.all([
|
|
368
|
+
getEvmAddress(creds),
|
|
369
|
+
getSolanaAddress(creds)
|
|
370
|
+
]);
|
|
371
|
+
return {
|
|
372
|
+
base: new TurnkeyEvmWallet(creds, "base", evmAddr),
|
|
373
|
+
sol: new TurnkeySvmWallet(creds, "sol", solAddr)
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
var TurnkeyEvmWallet, TurnkeySvmWallet;
|
|
332
377
|
var init_turnkey_wallet = __esm({
|
|
333
378
|
"src/wallet/turnkey-wallet.ts"() {
|
|
334
379
|
"use strict";
|
|
335
|
-
init_types();
|
|
336
|
-
init_config();
|
|
337
380
|
init_turnkey();
|
|
338
|
-
|
|
339
|
-
chain;
|
|
381
|
+
TurnkeyEvmWallet = class {
|
|
382
|
+
chain = "evm";
|
|
340
383
|
paymentChain;
|
|
341
384
|
address;
|
|
342
385
|
creds;
|
|
343
386
|
constructor(creds, chain, address) {
|
|
344
387
|
this.creds = creds;
|
|
345
388
|
this.paymentChain = chain;
|
|
346
|
-
this.chain = toSdkChain(chain);
|
|
347
389
|
this.address = address;
|
|
348
390
|
}
|
|
349
|
-
static async create(creds) {
|
|
350
|
-
const [evmAddr, solAddr] = await Promise.all([
|
|
351
|
-
getEvmAddress(creds),
|
|
352
|
-
getSolanaAddress(creds)
|
|
353
|
-
]);
|
|
354
|
-
return {
|
|
355
|
-
base: new _TurnkeyWallet(creds, "base", evmAddr),
|
|
356
|
-
sol: new _TurnkeyWallet(creds, "sol", solAddr)
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
391
|
async signMessage(message) {
|
|
360
|
-
|
|
361
|
-
let hashFunction;
|
|
362
|
-
if (isEvmChain(this.paymentChain)) {
|
|
363
|
-
const prefix = `Ethereum Signed Message:
|
|
392
|
+
const prefix = `Ethereum Signed Message:
|
|
364
393
|
${message.length}`;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
394
|
+
const prefixed = Buffer.concat([Buffer.from(prefix, "utf-8"), Buffer.from(message, "utf-8")]);
|
|
395
|
+
const sig = await turnkeySignRawPayload(
|
|
396
|
+
this.creds,
|
|
397
|
+
this.address,
|
|
398
|
+
prefixed.toString("hex"),
|
|
399
|
+
"HASH_FUNCTION_KECCAK256"
|
|
400
|
+
);
|
|
401
|
+
return formatEvmSignature(sig);
|
|
402
|
+
}
|
|
403
|
+
async signTransaction(serializedTx) {
|
|
404
|
+
const txBytes = Buffer.from(serializedTx, "base64");
|
|
372
405
|
const result = await turnkeyRequest(
|
|
373
|
-
"/public/v1/submit/
|
|
406
|
+
"/public/v1/submit/sign_transaction",
|
|
374
407
|
{
|
|
375
|
-
type: "
|
|
408
|
+
type: "ACTIVITY_TYPE_SIGN_TRANSACTION_V2",
|
|
376
409
|
timestampMs: Date.now().toString(),
|
|
377
410
|
organizationId: this.creds.organizationId,
|
|
378
411
|
parameters: {
|
|
379
412
|
signWith: this.address,
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
hashFunction
|
|
413
|
+
unsignedTransaction: txBytes.toString("hex"),
|
|
414
|
+
type: "TRANSACTION_TYPE_ETHEREUM"
|
|
383
415
|
}
|
|
384
416
|
},
|
|
385
417
|
this.creds
|
|
386
418
|
);
|
|
387
|
-
const
|
|
388
|
-
if (!
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
419
|
+
const signedHex = result.activity?.result?.signTransactionResult?.signedTransaction;
|
|
420
|
+
if (!signedHex) throw new Error("Turnkey signTransaction: no signed tx in response");
|
|
421
|
+
return Buffer.from(signedHex, "hex").toString("base64");
|
|
422
|
+
}
|
|
423
|
+
async signTypedData(typedData) {
|
|
424
|
+
const digest = hashTypedData(typedData);
|
|
425
|
+
const payloadHex = digest.slice(2);
|
|
426
|
+
const sig = await turnkeySignRawPayload(
|
|
427
|
+
this.creds,
|
|
428
|
+
this.address,
|
|
429
|
+
payloadHex,
|
|
430
|
+
"HASH_FUNCTION_NO_OP"
|
|
431
|
+
);
|
|
432
|
+
return formatEvmSignature(sig);
|
|
433
|
+
}
|
|
434
|
+
async signRawHash(hash) {
|
|
435
|
+
const payloadHex = hash.startsWith("0x") ? hash.slice(2) : hash;
|
|
436
|
+
const sig = await turnkeySignRawPayload(
|
|
437
|
+
this.creds,
|
|
438
|
+
this.address,
|
|
439
|
+
payloadHex,
|
|
440
|
+
"HASH_FUNCTION_NO_OP"
|
|
441
|
+
);
|
|
442
|
+
return formatEvmSignature(sig);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
TurnkeySvmWallet = class {
|
|
446
|
+
chain = "solana";
|
|
447
|
+
paymentChain;
|
|
448
|
+
address;
|
|
449
|
+
creds;
|
|
450
|
+
constructor(creds, chain, address) {
|
|
451
|
+
this.creds = creds;
|
|
452
|
+
this.paymentChain = chain;
|
|
453
|
+
this.address = address;
|
|
454
|
+
}
|
|
455
|
+
async signMessage(message) {
|
|
456
|
+
const sig = await turnkeySignRawPayload(
|
|
457
|
+
this.creds,
|
|
458
|
+
this.address,
|
|
459
|
+
Buffer.from(message, "utf-8").toString("hex"),
|
|
460
|
+
"HASH_FUNCTION_NOT_APPLICABLE"
|
|
461
|
+
);
|
|
462
|
+
return `${sig.r}${sig.s}`;
|
|
394
463
|
}
|
|
395
464
|
async signTransaction(serializedTx) {
|
|
396
465
|
const txBytes = Buffer.from(serializedTx, "base64");
|
|
397
|
-
const unsignedHex = txBytes.toString("hex");
|
|
398
|
-
const txType = isEvmChain(this.paymentChain) ? "TRANSACTION_TYPE_ETHEREUM" : "TRANSACTION_TYPE_SOLANA";
|
|
399
466
|
const result = await turnkeyRequest(
|
|
400
467
|
"/public/v1/submit/sign_transaction",
|
|
401
468
|
{
|
|
@@ -404,8 +471,8 @@ ${message.length}`;
|
|
|
404
471
|
organizationId: this.creds.organizationId,
|
|
405
472
|
parameters: {
|
|
406
473
|
signWith: this.address,
|
|
407
|
-
unsignedTransaction:
|
|
408
|
-
type:
|
|
474
|
+
unsignedTransaction: txBytes.toString("hex"),
|
|
475
|
+
type: "TRANSACTION_TYPE_SOLANA"
|
|
409
476
|
}
|
|
410
477
|
},
|
|
411
478
|
this.creds
|
|
@@ -426,7 +493,7 @@ __export(wallet_exports, {
|
|
|
426
493
|
});
|
|
427
494
|
function createWallet(config, mode) {
|
|
428
495
|
if (mode === "raw" && config.rawWallet) {
|
|
429
|
-
return
|
|
496
|
+
return createRawKeyWallet(config.rawWallet.key, config.rawWallet.chain);
|
|
430
497
|
}
|
|
431
498
|
if (mode === "turnkey" && config.turnkey) {
|
|
432
499
|
const chain = config.walletChain ?? "base";
|
|
@@ -437,7 +504,7 @@ function createWallet(config, mode) {
|
|
|
437
504
|
Please re-login to resolve addresses: chainstream login`
|
|
438
505
|
);
|
|
439
506
|
}
|
|
440
|
-
return new
|
|
507
|
+
return isEvmChain(chain) ? new TurnkeyEvmWallet(config.turnkey, chain, address) : new TurnkeySvmWallet(config.turnkey, chain, address);
|
|
441
508
|
}
|
|
442
509
|
throw new Error(
|
|
443
510
|
"No wallet configured. Run:\n chainstream login # Create Turnkey wallet\n chainstream wallet set-raw # Use raw private key (dev)"
|
|
@@ -445,11 +512,11 @@ Please re-login to resolve addresses: chainstream login`
|
|
|
445
512
|
}
|
|
446
513
|
async function createWalletWithAddresses(config, mode) {
|
|
447
514
|
if (mode === "raw" && config.rawWallet) {
|
|
448
|
-
const w =
|
|
515
|
+
const w = createRawKeyWallet(config.rawWallet.key, config.rawWallet.chain);
|
|
449
516
|
return isEvmChain(config.rawWallet.chain) ? { base: w } : { sol: w };
|
|
450
517
|
}
|
|
451
518
|
if (mode === "turnkey" && config.turnkey) {
|
|
452
|
-
const wallets = await
|
|
519
|
+
const wallets = await createTurnkeyWallets(config.turnkey);
|
|
453
520
|
return { base: wallets.base, sol: wallets.sol };
|
|
454
521
|
}
|
|
455
522
|
throw new Error("No wallet configured.");
|
|
@@ -468,6 +535,7 @@ var x402_exports = {};
|
|
|
468
535
|
__export(x402_exports, {
|
|
469
536
|
getPricing: () => getPricing,
|
|
470
537
|
getX402Fetch: () => getX402Fetch,
|
|
538
|
+
selectPaymentMethod: () => selectPaymentMethod,
|
|
471
539
|
selectPlanInteractive: () => selectPlanInteractive
|
|
472
540
|
});
|
|
473
541
|
import { x402Client } from "@x402/core/client";
|
|
@@ -475,7 +543,7 @@ import { wrapFetchWithPayment } from "@x402/fetch";
|
|
|
475
543
|
import { ExactEvmScheme } from "@x402/evm/exact/client";
|
|
476
544
|
import { ExactSvmScheme } from "@x402/svm/exact/client";
|
|
477
545
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
478
|
-
import { hashTypedData } from "viem";
|
|
546
|
+
import { hashTypedData as hashTypedData2 } from "viem";
|
|
479
547
|
import { createKeyPairSignerFromBytes } from "@solana/kit";
|
|
480
548
|
import * as readline from "readline/promises";
|
|
481
549
|
function createTurnkeyPaymentAccount(creds) {
|
|
@@ -486,7 +554,7 @@ function createTurnkeyPaymentAccount(creds) {
|
|
|
486
554
|
source: "custom",
|
|
487
555
|
publicKey: "0x",
|
|
488
556
|
async signTypedData(args) {
|
|
489
|
-
const digest =
|
|
557
|
+
const digest = hashTypedData2(args);
|
|
490
558
|
const result = await turnkeyRequest(
|
|
491
559
|
"/public/v1/submit/sign_raw_payload",
|
|
492
560
|
{
|
|
@@ -608,6 +676,15 @@ async function getPricing(baseUrl) {
|
|
|
608
676
|
if (!resp.ok) throw new Error(`Failed to get pricing (${resp.status})`);
|
|
609
677
|
return resp.json();
|
|
610
678
|
}
|
|
679
|
+
async function selectPaymentMethod() {
|
|
680
|
+
process.stderr.write("\n[chainstream] Choose payment method:\n");
|
|
681
|
+
process.stderr.write(" 1. x402 (USDC on Base/Solana)\n");
|
|
682
|
+
process.stderr.write(" 2. MPP Tempo (USDC.e on Tempo)\n\n");
|
|
683
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
684
|
+
const answer = await rl.question("Select method (1-2): ");
|
|
685
|
+
rl.close();
|
|
686
|
+
return answer.trim() === "2" ? "mpp" : "x402";
|
|
687
|
+
}
|
|
611
688
|
async function selectPlanInteractive(baseUrl) {
|
|
612
689
|
const pricing = await getPricing(baseUrl);
|
|
613
690
|
const plans = pricing.plans.sort((a, b) => a.priceUsd - b.priceUsd);
|
|
@@ -677,29 +754,35 @@ function createClient() {
|
|
|
677
754
|
"Not authenticated. Run one of:\n chainstream login # Create ChainStream Wallet (no email)\n chainstream login --email # Email OTP login\n chainstream wallet set-raw # Import private key (dev)\n chainstream config set --key apiKey --value <key> # API key only"
|
|
678
755
|
);
|
|
679
756
|
}
|
|
680
|
-
function requireWallet() {
|
|
681
|
-
const config = loadConfig();
|
|
682
|
-
const walletMode = getWalletMode(config);
|
|
683
|
-
if (!walletMode) {
|
|
684
|
-
throw new Error(
|
|
685
|
-
"Wallet required for this operation. Run:\n chainstream login # Create ChainStream Wallet\n chainstream wallet set-raw # Dev: use raw private key"
|
|
686
|
-
);
|
|
687
|
-
}
|
|
688
|
-
return createClient();
|
|
689
|
-
}
|
|
690
757
|
async function callWithAutoPayment(fn, retried = false) {
|
|
691
758
|
try {
|
|
692
759
|
return await fn();
|
|
693
760
|
} catch (err) {
|
|
694
761
|
const paymentInfo = extractPaymentInfo(err);
|
|
695
|
-
if (paymentInfo && !retried
|
|
762
|
+
if (paymentInfo && !retried) {
|
|
696
763
|
const config = loadConfig();
|
|
697
764
|
const chosenPlan = await selectPlanInteractive(config.baseUrl);
|
|
765
|
+
const method = _wallet ? await selectPaymentMethod() : "mpp";
|
|
766
|
+
if (method === "mpp") {
|
|
767
|
+
const mppUrl = `${config.baseUrl}/mpp/purchase?plan=${encodeURIComponent(chosenPlan)}`;
|
|
768
|
+
process.stderr.write(
|
|
769
|
+
`
|
|
770
|
+
[chainstream] To purchase via MPP (USDC.e on Tempo), run:
|
|
771
|
+
tempo request ${mppUrl}
|
|
772
|
+
|
|
773
|
+
After purchase, set the API key:
|
|
774
|
+
chainstream config set --key apiKey --value <key from response>
|
|
775
|
+
|
|
776
|
+
`
|
|
777
|
+
);
|
|
778
|
+
throw err;
|
|
779
|
+
}
|
|
780
|
+
if (!_wallet) throw err;
|
|
698
781
|
const purchaseUrl = replacePlanInUrl(
|
|
699
782
|
resolvePurchaseUrl(config.baseUrl, paymentInfo),
|
|
700
783
|
chosenPlan
|
|
701
784
|
);
|
|
702
|
-
process.stderr.write(`[chainstream] Purchasing ${chosenPlan} plan...
|
|
785
|
+
process.stderr.write(`[chainstream] Purchasing ${chosenPlan} plan via x402...
|
|
703
786
|
`);
|
|
704
787
|
const x402Fetch = await getX402Fetch(config);
|
|
705
788
|
const resp = await x402Fetch(purchaseUrl);
|
|
@@ -791,11 +874,6 @@ function validateAddress(address, chain) {
|
|
|
791
874
|
throw new Error(`Invalid address for chain "${chain}": "${address}"`);
|
|
792
875
|
}
|
|
793
876
|
}
|
|
794
|
-
function validateSlippage(value) {
|
|
795
|
-
if (value < 1e-3 || value > 0.5) {
|
|
796
|
-
throw new Error(`Invalid slippage: ${value}. Must be between 0.001 (0.1%) and 0.5 (50%).`);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
877
|
function resolveCurrency(nameOrAddress, chain) {
|
|
800
878
|
const upper = nameOrAddress.toUpperCase();
|
|
801
879
|
const resolved = CURRENCY_MAP[chain]?.[upper];
|
|
@@ -804,13 +882,8 @@ function resolveCurrency(nameOrAddress, chain) {
|
|
|
804
882
|
}
|
|
805
883
|
|
|
806
884
|
// src/lib/output.ts
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
bsc: "https://bscscan.com/tx/",
|
|
810
|
-
eth: "https://etherscan.io/tx/"
|
|
811
|
-
};
|
|
812
|
-
function printResult(data, raw) {
|
|
813
|
-
if (raw) {
|
|
885
|
+
function printResult(data, json) {
|
|
886
|
+
if (json) {
|
|
814
887
|
process.stdout.write(JSON.stringify(data) + "\n");
|
|
815
888
|
} else {
|
|
816
889
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
@@ -828,27 +901,23 @@ function exitOnError(err) {
|
|
|
828
901
|
}
|
|
829
902
|
process.exit(1);
|
|
830
903
|
}
|
|
831
|
-
function explorerUrl(chain, txHash) {
|
|
832
|
-
const base = EXPLORERS[chain] ?? EXPLORERS["eth"];
|
|
833
|
-
return `${base}${txHash}`;
|
|
834
|
-
}
|
|
835
904
|
|
|
836
905
|
// src/commands/token.ts
|
|
837
906
|
function registerTokenCommands(program2) {
|
|
838
907
|
const token = program2.command("token").description("Token information and analytics");
|
|
839
|
-
token.command("search").description("Search tokens by keyword").requiredOption("--keyword <keyword>", "Search keyword (name, symbol, or address)").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--limit <n>", "Max results", "20").
|
|
908
|
+
token.command("search").description("Search tokens by keyword").requiredOption("--keyword <keyword>", "Search keyword (name, symbol, or address)").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--limit <n>", "Max results", "20").action(async (opts, cmd) => {
|
|
840
909
|
try {
|
|
841
910
|
validateChain(opts.chain);
|
|
842
911
|
const client = createClient();
|
|
843
912
|
const result = await callWithAutoPayment(
|
|
844
913
|
() => client.token.search({ q: opts.keyword, chains: [opts.chain], limit: Number(opts.limit) })
|
|
845
914
|
);
|
|
846
|
-
printResult(result,
|
|
915
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
847
916
|
} catch (err) {
|
|
848
917
|
exitOnError(err);
|
|
849
918
|
}
|
|
850
919
|
});
|
|
851
|
-
token.command("info").description("Get full token detail").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").
|
|
920
|
+
token.command("info").description("Get full token detail").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").action(async (opts, cmd) => {
|
|
852
921
|
try {
|
|
853
922
|
validateChain(opts.chain);
|
|
854
923
|
validateAddress(opts.address, opts.chain);
|
|
@@ -856,12 +925,12 @@ function registerTokenCommands(program2) {
|
|
|
856
925
|
const result = await callWithAutoPayment(
|
|
857
926
|
() => client.token.getToken(opts.chain, opts.address)
|
|
858
927
|
);
|
|
859
|
-
printResult(result,
|
|
928
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
860
929
|
} catch (err) {
|
|
861
930
|
exitOnError(err);
|
|
862
931
|
}
|
|
863
932
|
});
|
|
864
|
-
token.command("security").description("Check token security (honeypot, mint auth, freeze auth)").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").
|
|
933
|
+
token.command("security").description("Check token security (honeypot, mint auth, freeze auth)").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").action(async (opts, cmd) => {
|
|
865
934
|
try {
|
|
866
935
|
validateChain(opts.chain);
|
|
867
936
|
validateAddress(opts.address, opts.chain);
|
|
@@ -869,12 +938,12 @@ function registerTokenCommands(program2) {
|
|
|
869
938
|
const result = await callWithAutoPayment(
|
|
870
939
|
() => client.token.getSecurity(opts.chain, opts.address)
|
|
871
940
|
);
|
|
872
|
-
printResult(result,
|
|
941
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
873
942
|
} catch (err) {
|
|
874
943
|
exitOnError(err);
|
|
875
944
|
}
|
|
876
945
|
});
|
|
877
|
-
token.command("holders").description("Get top token holders").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").option("--limit <n>", "Max results", "20").
|
|
946
|
+
token.command("holders").description("Get top token holders").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").option("--limit <n>", "Max results", "20").action(async (opts, cmd) => {
|
|
878
947
|
try {
|
|
879
948
|
validateChain(opts.chain);
|
|
880
949
|
validateAddress(opts.address, opts.chain);
|
|
@@ -882,12 +951,12 @@ function registerTokenCommands(program2) {
|
|
|
882
951
|
const result = await callWithAutoPayment(
|
|
883
952
|
() => client.token.getTopHolders(opts.chain, opts.address, { limit: Number(opts.limit) })
|
|
884
953
|
);
|
|
885
|
-
printResult(result,
|
|
954
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
886
955
|
} catch (err) {
|
|
887
956
|
exitOnError(err);
|
|
888
957
|
}
|
|
889
958
|
});
|
|
890
|
-
token.command("candles").description("Get OHLCV candlestick data").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").requiredOption("--resolution <res>", "Resolution: 1m/5m/15m/1h/4h/1d").option("--from <timestamp>", "Start time (Unix seconds)").option("--to <timestamp>", "End time (Unix seconds)").option("--limit <n>", "Max candles", "100").
|
|
959
|
+
token.command("candles").description("Get OHLCV candlestick data").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").requiredOption("--resolution <res>", "Resolution: 1m/5m/15m/1h/4h/1d").option("--from <timestamp>", "Start time (Unix seconds)").option("--to <timestamp>", "End time (Unix seconds)").option("--limit <n>", "Max candles", "100").action(async (opts, cmd) => {
|
|
891
960
|
try {
|
|
892
961
|
validateChain(opts.chain);
|
|
893
962
|
validateAddress(opts.address, opts.chain);
|
|
@@ -901,12 +970,12 @@ function registerTokenCommands(program2) {
|
|
|
901
970
|
const result = await callWithAutoPayment(
|
|
902
971
|
() => client.token.getCandles(opts.chain, opts.address, params)
|
|
903
972
|
);
|
|
904
|
-
printResult(result,
|
|
973
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
905
974
|
} catch (err) {
|
|
906
975
|
exitOnError(err);
|
|
907
976
|
}
|
|
908
977
|
});
|
|
909
|
-
token.command("pools").description("Get liquidity pools for a token").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").
|
|
978
|
+
token.command("pools").description("Get liquidity pools for a token").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Token contract address").action(async (opts, cmd) => {
|
|
910
979
|
try {
|
|
911
980
|
validateChain(opts.chain);
|
|
912
981
|
validateAddress(opts.address, opts.chain);
|
|
@@ -914,7 +983,7 @@ function registerTokenCommands(program2) {
|
|
|
914
983
|
const result = await callWithAutoPayment(
|
|
915
984
|
() => client.token.getPools(opts.chain, opts.address)
|
|
916
985
|
);
|
|
917
|
-
printResult(result,
|
|
986
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
918
987
|
} catch (err) {
|
|
919
988
|
exitOnError(err);
|
|
920
989
|
}
|
|
@@ -924,7 +993,7 @@ function registerTokenCommands(program2) {
|
|
|
924
993
|
// src/commands/market.ts
|
|
925
994
|
function registerMarketCommands(program2) {
|
|
926
995
|
const market = program2.command("market").description("Market data and trending tokens");
|
|
927
|
-
market.command("trending").description("Get hot/trending tokens").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--duration <dur>", "Duration: 1h/6h/24h").option("--limit <n>", "Max results").
|
|
996
|
+
market.command("trending").description("Get hot/trending tokens").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--duration <dur>", "Duration: 1h/6h/24h").option("--limit <n>", "Max results").action(async (opts, cmd) => {
|
|
928
997
|
try {
|
|
929
998
|
validateChain(opts.chain);
|
|
930
999
|
const client = createClient();
|
|
@@ -933,12 +1002,12 @@ function registerMarketCommands(program2) {
|
|
|
933
1002
|
const result = await callWithAutoPayment(
|
|
934
1003
|
() => client.ranking.getHotTokens(opts.chain, opts.duration, params)
|
|
935
1004
|
);
|
|
936
|
-
printResult(result,
|
|
1005
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
937
1006
|
} catch (err) {
|
|
938
1007
|
exitOnError(err);
|
|
939
1008
|
}
|
|
940
1009
|
});
|
|
941
|
-
market.command("new").description("Get newly created tokens").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--limit <n>", "Max results").
|
|
1010
|
+
market.command("new").description("Get newly created tokens").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--limit <n>", "Max results").action(async (opts, cmd) => {
|
|
942
1011
|
try {
|
|
943
1012
|
validateChain(opts.chain);
|
|
944
1013
|
const client = createClient();
|
|
@@ -947,12 +1016,12 @@ function registerMarketCommands(program2) {
|
|
|
947
1016
|
const result = await callWithAutoPayment(
|
|
948
1017
|
() => client.ranking.getNewTokens(opts.chain, params)
|
|
949
1018
|
);
|
|
950
|
-
printResult(result,
|
|
1019
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
951
1020
|
} catch (err) {
|
|
952
1021
|
exitOnError(err);
|
|
953
1022
|
}
|
|
954
1023
|
});
|
|
955
|
-
market.command("trades").description("Get recent trades").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--token <address>", "Filter by token address").option("--limit <n>", "Max results").
|
|
1024
|
+
market.command("trades").description("Get recent trades").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").option("--token <address>", "Filter by token address").option("--limit <n>", "Max results").action(async (opts, cmd) => {
|
|
956
1025
|
try {
|
|
957
1026
|
validateChain(opts.chain);
|
|
958
1027
|
const client = createClient();
|
|
@@ -962,7 +1031,7 @@ function registerMarketCommands(program2) {
|
|
|
962
1031
|
const result = await callWithAutoPayment(
|
|
963
1032
|
() => client.trade.getTrades(opts.chain, params)
|
|
964
1033
|
);
|
|
965
|
-
printResult(result,
|
|
1034
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
966
1035
|
} catch (err) {
|
|
967
1036
|
exitOnError(err);
|
|
968
1037
|
}
|
|
@@ -973,8 +1042,25 @@ function registerMarketCommands(program2) {
|
|
|
973
1042
|
init_config();
|
|
974
1043
|
import * as readline2 from "readline/promises";
|
|
975
1044
|
function registerWalletCommands(program2) {
|
|
976
|
-
const wallet = program2.command("wallet").description("Wallet analytics and
|
|
977
|
-
wallet.command("
|
|
1045
|
+
const wallet = program2.command("wallet").description("Wallet analytics, management, and signing");
|
|
1046
|
+
wallet.command("sign").description("Sign a serialized transaction").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--tx <base64>", "Base64-encoded unsigned transaction (serializedTx)").action(async (opts, cmd) => {
|
|
1047
|
+
try {
|
|
1048
|
+
validateChain(opts.chain);
|
|
1049
|
+
const { createWallet: createWallet2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
1050
|
+
const { getWalletMode: getWalletMode2, isSolanaChain: isSolanaChain2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1051
|
+
const config = loadConfig();
|
|
1052
|
+
const walletMode = getWalletMode2(config);
|
|
1053
|
+
if (!walletMode) throw new Error("Wallet required for signing. Run: chainstream login");
|
|
1054
|
+
const signChain = isSolanaChain2(opts.chain) ? "sol" : "base";
|
|
1055
|
+
const signConfig = { ...config, walletChain: signChain };
|
|
1056
|
+
const w = createWallet2(signConfig, walletMode);
|
|
1057
|
+
const signedTx = await w.signTransaction(opts.tx);
|
|
1058
|
+
printResult({ signedTx }, cmd.optsWithGlobals().json);
|
|
1059
|
+
} catch (err) {
|
|
1060
|
+
exitOnError(err);
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
wallet.command("profile").description("Wallet profile: PnL + net worth + top holdings").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").action(async (opts, cmd) => {
|
|
978
1064
|
try {
|
|
979
1065
|
validateChain(opts.chain);
|
|
980
1066
|
validateAddress(opts.address, opts.chain);
|
|
@@ -986,12 +1072,12 @@ function registerWalletCommands(program2) {
|
|
|
986
1072
|
client.wallet.getTokensBalance(opts.chain, opts.address)
|
|
987
1073
|
])
|
|
988
1074
|
);
|
|
989
|
-
printResult({ pnl, netWorth, balance },
|
|
1075
|
+
printResult({ pnl, netWorth, balance }, cmd.optsWithGlobals().json);
|
|
990
1076
|
} catch (err) {
|
|
991
1077
|
exitOnError(err);
|
|
992
1078
|
}
|
|
993
1079
|
});
|
|
994
|
-
wallet.command("pnl").description("Get wallet PnL details").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").
|
|
1080
|
+
wallet.command("pnl").description("Get wallet PnL details").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").action(async (opts, cmd) => {
|
|
995
1081
|
try {
|
|
996
1082
|
validateChain(opts.chain);
|
|
997
1083
|
validateAddress(opts.address, opts.chain);
|
|
@@ -999,12 +1085,12 @@ function registerWalletCommands(program2) {
|
|
|
999
1085
|
const result = await callWithAutoPayment(
|
|
1000
1086
|
() => client.wallet.getPnl(opts.chain, opts.address)
|
|
1001
1087
|
);
|
|
1002
|
-
printResult(result,
|
|
1088
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1003
1089
|
} catch (err) {
|
|
1004
1090
|
exitOnError(err);
|
|
1005
1091
|
}
|
|
1006
1092
|
});
|
|
1007
|
-
wallet.command("holdings").description("Get wallet token balances").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").option("--limit <n>", "Max results").
|
|
1093
|
+
wallet.command("holdings").description("Get wallet token balances").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").option("--limit <n>", "Max results").action(async (opts, cmd) => {
|
|
1008
1094
|
try {
|
|
1009
1095
|
validateChain(opts.chain);
|
|
1010
1096
|
validateAddress(opts.address, opts.chain);
|
|
@@ -1014,12 +1100,12 @@ function registerWalletCommands(program2) {
|
|
|
1014
1100
|
const result = await callWithAutoPayment(
|
|
1015
1101
|
() => client.wallet.getTokensBalance(opts.chain, opts.address, params)
|
|
1016
1102
|
);
|
|
1017
|
-
printResult(result,
|
|
1103
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1018
1104
|
} catch (err) {
|
|
1019
1105
|
exitOnError(err);
|
|
1020
1106
|
}
|
|
1021
1107
|
});
|
|
1022
|
-
wallet.command("activity").description("Get wallet transfer history").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").option("--limit <n>", "Max results").
|
|
1108
|
+
wallet.command("activity").description("Get wallet transfer history").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--address <address>", "Wallet address").option("--limit <n>", "Max results").action(async (opts, cmd) => {
|
|
1023
1109
|
try {
|
|
1024
1110
|
validateChain(opts.chain);
|
|
1025
1111
|
validateAddress(opts.address, opts.chain);
|
|
@@ -1029,42 +1115,46 @@ function registerWalletCommands(program2) {
|
|
|
1029
1115
|
const result = await callWithAutoPayment(
|
|
1030
1116
|
() => client.wallet.getWalletTransfers(opts.chain, opts.address, params)
|
|
1031
1117
|
);
|
|
1032
|
-
printResult(result,
|
|
1118
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1033
1119
|
} catch (err) {
|
|
1034
1120
|
exitOnError(err);
|
|
1035
1121
|
}
|
|
1036
1122
|
});
|
|
1037
|
-
wallet.command("address").description("Show current wallet addresses").action(async () => {
|
|
1123
|
+
wallet.command("address").description("Show current wallet addresses").action(async (_opts, cmd) => {
|
|
1038
1124
|
try {
|
|
1125
|
+
const json = cmd.optsWithGlobals().json;
|
|
1039
1126
|
const config = loadConfig();
|
|
1040
1127
|
const walletMode = (await Promise.resolve().then(() => (init_config(), config_exports))).getWalletMode(config);
|
|
1128
|
+
const addresses = {};
|
|
1041
1129
|
if (walletMode === "turnkey" && config.turnkey) {
|
|
1042
1130
|
if (config.turnkey.evmAddress || config.turnkey.solanaAddress) {
|
|
1043
|
-
if (config.turnkey.evmAddress)
|
|
1044
|
-
|
|
1045
|
-
if (config.turnkey.solanaAddress) process.stdout.write(`Solana: ${config.turnkey.solanaAddress}
|
|
1046
|
-
`);
|
|
1131
|
+
if (config.turnkey.evmAddress) addresses.base = config.turnkey.evmAddress;
|
|
1132
|
+
if (config.turnkey.solanaAddress) addresses.solana = config.turnkey.solanaAddress;
|
|
1047
1133
|
} else {
|
|
1048
1134
|
const { createWalletWithAddresses: createWalletWithAddresses2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
1049
1135
|
const wallets = await createWalletWithAddresses2(config, "turnkey");
|
|
1050
|
-
if (wallets.base)
|
|
1051
|
-
|
|
1052
|
-
if (wallets.sol) process.stdout.write(`Solana: ${wallets.sol.address}
|
|
1053
|
-
`);
|
|
1136
|
+
if (wallets.base) addresses.base = wallets.base.address;
|
|
1137
|
+
if (wallets.sol) addresses.solana = wallets.sol.address;
|
|
1054
1138
|
}
|
|
1055
1139
|
} else if (config.rawWallet) {
|
|
1056
1140
|
const { createWallet: createWallet2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
1057
1141
|
const w = createWallet2(config, "raw");
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1142
|
+
addresses[w.paymentChain] = w.address;
|
|
1143
|
+
}
|
|
1144
|
+
if (Object.keys(addresses).length === 0) {
|
|
1145
|
+
if (json) {
|
|
1146
|
+
printResult({ error: "No wallet configured" }, true);
|
|
1147
|
+
} else {
|
|
1148
|
+
process.stdout.write("No wallet configured. Run: chainstream login\n");
|
|
1149
|
+
}
|
|
1150
|
+
return;
|
|
1062
1151
|
}
|
|
1152
|
+
printResult(addresses, json);
|
|
1063
1153
|
} catch (err) {
|
|
1064
1154
|
exitOnError(err);
|
|
1065
1155
|
}
|
|
1066
1156
|
});
|
|
1067
|
-
wallet.command("balance").description("Show current wallet balance").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").
|
|
1157
|
+
wallet.command("balance").description("Show current wallet balance").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").action(async (opts, cmd) => {
|
|
1068
1158
|
try {
|
|
1069
1159
|
validateChain(opts.chain);
|
|
1070
1160
|
const config = loadConfig();
|
|
@@ -1086,34 +1176,38 @@ function registerWalletCommands(program2) {
|
|
|
1086
1176
|
const result = await callWithAutoPayment(
|
|
1087
1177
|
() => client.wallet.getTokensBalance(opts.chain, address)
|
|
1088
1178
|
);
|
|
1089
|
-
printResult(result,
|
|
1179
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1090
1180
|
} catch (err) {
|
|
1091
1181
|
exitOnError(err);
|
|
1092
1182
|
}
|
|
1093
1183
|
});
|
|
1094
|
-
wallet.command("set-raw").description("Set raw private key (dev/testing only)").requiredOption("--chain <chain>", "Chain: base/sol").action(async (opts) => {
|
|
1184
|
+
wallet.command("set-raw").description("Set raw private key (dev/testing only)").requiredOption("--chain <chain>", "Chain: base/sol").action(async (opts, cmd) => {
|
|
1095
1185
|
try {
|
|
1186
|
+
const json = cmd.optsWithGlobals().json;
|
|
1096
1187
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1188
|
+
if (!json) {
|
|
1189
|
+
process.stdout.write("WARNING: Raw private key will be stored in plaintext.\n");
|
|
1190
|
+
process.stdout.write(" Use Turnkey (chainstream login) for production.\n\n");
|
|
1191
|
+
}
|
|
1192
|
+
const key = await rl.question(json ? "" : "Enter private key: ");
|
|
1100
1193
|
rl.close();
|
|
1101
1194
|
if (!key.trim()) throw new Error("Empty key provided.");
|
|
1102
1195
|
updateConfig({
|
|
1103
1196
|
rawWallet: { key: key.trim(), chain: opts.chain }
|
|
1104
1197
|
});
|
|
1105
|
-
|
|
1106
|
-
|
|
1198
|
+
const { createWallet: createWallet2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
1199
|
+
const w = createWallet2(loadConfig(), "raw");
|
|
1200
|
+
printResult({ chain: opts.chain, address: w.address }, json);
|
|
1107
1201
|
} catch (err) {
|
|
1108
1202
|
exitOnError(err);
|
|
1109
1203
|
}
|
|
1110
1204
|
});
|
|
1111
|
-
wallet.command("pricing").description("Show available x402 quota plans").
|
|
1205
|
+
wallet.command("pricing").description("Show available x402 quota plans").action(async (_opts, cmd) => {
|
|
1112
1206
|
try {
|
|
1113
1207
|
const config = loadConfig();
|
|
1114
1208
|
const { getPricing: getPricing2 } = await Promise.resolve().then(() => (init_x402(), x402_exports));
|
|
1115
1209
|
const plans = await getPricing2(config.baseUrl);
|
|
1116
|
-
printResult(plans,
|
|
1210
|
+
printResult(plans, cmd.optsWithGlobals().json);
|
|
1117
1211
|
} catch (err) {
|
|
1118
1212
|
exitOnError(err);
|
|
1119
1213
|
}
|
|
@@ -1121,121 +1215,136 @@ function registerWalletCommands(program2) {
|
|
|
1121
1215
|
}
|
|
1122
1216
|
|
|
1123
1217
|
// src/commands/dex.ts
|
|
1124
|
-
import * as readline3 from "readline/promises";
|
|
1125
1218
|
function registerDexCommands(program2) {
|
|
1126
|
-
const dex = program2.command("dex").description("DEX
|
|
1127
|
-
dex.command("
|
|
1219
|
+
const dex = program2.command("dex").description("DEX route, swap, and token creation (returns unsigned transactions)");
|
|
1220
|
+
dex.command("route").description("Get aggregated route + build unsigned transaction").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--from <address>", "Sender wallet address").requiredOption("--input-token <addr>", "Input token (address or SOL/ETH/BNB/USDC)").requiredOption("--output-token <addr>", "Output token (address or SOL/ETH/BNB/USDC)").requiredOption("--amount <amount>", "Input amount (smallest unit)").option("--slippage <n>", "Slippage tolerance (0-100, e.g. 5 = 5%)", "5").option("--dex <dex>", "Specific DEX protocol (e.g. jupiter, kyberswap)").option("--recipient <addr>", "Recipient address (if different from sender)").option("--anti-mev", "Enable anti-MEV protection").option("--gas-price <n>", "Gas price (EVM, numeric string)").option("--gas-limit <n>", "Gas limit (EVM, numeric string)").option("--max-fee-per-gas <n>", "Max fee per gas (EVM EIP-1559)").option("--max-priority-fee-per-gas <n>", "Max priority fee per gas (EVM EIP-1559)").action(async (opts, cmd) => {
|
|
1128
1221
|
try {
|
|
1129
1222
|
validateChain(opts.chain);
|
|
1223
|
+
validateAddress(opts.from, opts.chain);
|
|
1130
1224
|
const inputToken = resolveCurrency(opts.inputToken, opts.chain);
|
|
1131
1225
|
const outputToken = resolveCurrency(opts.outputToken, opts.chain);
|
|
1132
1226
|
const client = createClient();
|
|
1227
|
+
const body = {
|
|
1228
|
+
dex: opts.dex ?? "jupiter",
|
|
1229
|
+
userAddress: opts.from,
|
|
1230
|
+
inputMint: inputToken,
|
|
1231
|
+
outputMint: outputToken,
|
|
1232
|
+
amount: opts.amount,
|
|
1233
|
+
swapMode: "ExactIn",
|
|
1234
|
+
slippage: Number(opts.slippage)
|
|
1235
|
+
};
|
|
1236
|
+
if (opts.recipient) body.recipientAddress = opts.recipient;
|
|
1237
|
+
if (opts.antiMev) body.isAntiMev = true;
|
|
1238
|
+
if (opts.gasPrice) body.gasPrice = opts.gasPrice;
|
|
1239
|
+
if (opts.gasLimit) body.gasLimit = opts.gasLimit;
|
|
1240
|
+
if (opts.maxFeePerGas) body.maxFeePerGas = opts.maxFeePerGas;
|
|
1241
|
+
if (opts.maxPriorityFeePerGas) body.maxPriorityFeePerGas = opts.maxPriorityFeePerGas;
|
|
1133
1242
|
const result = await callWithAutoPayment(
|
|
1134
|
-
() => client.dex.
|
|
1135
|
-
inputMint: inputToken,
|
|
1136
|
-
outputMint: outputToken,
|
|
1137
|
-
amount: opts.amount
|
|
1138
|
-
})
|
|
1243
|
+
() => client.dex.route(opts.chain, body)
|
|
1139
1244
|
);
|
|
1140
|
-
printResult(result,
|
|
1245
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1141
1246
|
} catch (err) {
|
|
1142
1247
|
exitOnError(err);
|
|
1143
1248
|
}
|
|
1144
1249
|
});
|
|
1145
|
-
dex.command("swap").description("
|
|
1250
|
+
dex.command("swap").description("Build unsigned swap transaction").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--from <address>", "Sender wallet address").requiredOption("--input-token <addr>", "Input token (address or SOL/ETH/BNB/USDC)").requiredOption("--output-token <addr>", "Output token (address or SOL/ETH/BNB/USDC)").requiredOption("--amount <amount>", "Input amount (smallest unit)").option("--slippage <n>", "Slippage tolerance (0-100, e.g. 5 = 5%)", "5").option("--dex <dex>", "Specific DEX protocol").action(async (opts, cmd) => {
|
|
1146
1251
|
try {
|
|
1147
1252
|
validateChain(opts.chain);
|
|
1148
1253
|
validateAddress(opts.from, opts.chain);
|
|
1149
|
-
if (opts.slippage) validateSlippage(Number(opts.slippage));
|
|
1150
1254
|
const inputToken = resolveCurrency(opts.inputToken, opts.chain);
|
|
1151
1255
|
const outputToken = resolveCurrency(opts.outputToken, opts.chain);
|
|
1152
|
-
const client =
|
|
1153
|
-
|
|
1154
|
-
const quote = await callWithAutoPayment(
|
|
1155
|
-
() => client.dex.quote(opts.chain, {
|
|
1156
|
-
inputMint: inputToken,
|
|
1157
|
-
outputMint: outputToken,
|
|
1158
|
-
amount: opts.amount
|
|
1159
|
-
})
|
|
1160
|
-
);
|
|
1161
|
-
process.stderr.write("\n--- Swap Summary ---\n");
|
|
1162
|
-
process.stderr.write(`Chain: ${opts.chain}
|
|
1163
|
-
`);
|
|
1164
|
-
process.stderr.write(`Input: ${inputToken}
|
|
1165
|
-
`);
|
|
1166
|
-
process.stderr.write(`Output: ${outputToken}
|
|
1167
|
-
`);
|
|
1168
|
-
process.stderr.write(`Amount: ${opts.amount}
|
|
1169
|
-
`);
|
|
1170
|
-
process.stderr.write(`Slippage: ${opts.slippage}
|
|
1171
|
-
`);
|
|
1172
|
-
process.stderr.write(`Quote: ${JSON.stringify(quote)}
|
|
1173
|
-
`);
|
|
1174
|
-
process.stderr.write("--------------------\n\n");
|
|
1175
|
-
if (!opts.yes) {
|
|
1176
|
-
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
1177
|
-
const answer = await rl.question("Confirm swap? (y/N): ");
|
|
1178
|
-
rl.close();
|
|
1179
|
-
if (answer.toLowerCase() !== "y") {
|
|
1180
|
-
process.stderr.write("Swap cancelled.\n");
|
|
1181
|
-
return;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
process.stderr.write("Building transaction...\n");
|
|
1185
|
-
const swapResult = await callWithAutoPayment(
|
|
1256
|
+
const client = createClient();
|
|
1257
|
+
const result = await callWithAutoPayment(
|
|
1186
1258
|
() => client.dex.swap(opts.chain, {
|
|
1259
|
+
dex: opts.dex ?? "jupiter",
|
|
1187
1260
|
userAddress: opts.from,
|
|
1188
1261
|
inputMint: inputToken,
|
|
1189
1262
|
outputMint: outputToken,
|
|
1190
1263
|
amount: opts.amount,
|
|
1264
|
+
swapMode: "ExactIn",
|
|
1191
1265
|
slippage: Number(opts.slippage)
|
|
1192
1266
|
})
|
|
1193
1267
|
);
|
|
1194
|
-
|
|
1195
|
-
const { loadConfig: loadConfig2, getWalletMode: getWalletMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1196
|
-
const config = loadConfig2();
|
|
1197
|
-
const walletMode = getWalletMode2(config);
|
|
1198
|
-
if (!walletMode) throw new Error("Wallet required for swap.");
|
|
1199
|
-
const wallet = createWallet2(config, walletMode);
|
|
1200
|
-
process.stderr.write("Signing transaction...\n");
|
|
1201
|
-
const signedTx = await wallet.signTransaction(swapResult.serializedTx);
|
|
1202
|
-
process.stderr.write("Broadcasting transaction...\n");
|
|
1203
|
-
const sendResult = await client.transaction.send(opts.chain, {
|
|
1204
|
-
signedTx
|
|
1205
|
-
});
|
|
1206
|
-
if (sendResult.jobId) {
|
|
1207
|
-
process.stderr.write(`Job ${sendResult.jobId} submitted. Waiting for confirmation...
|
|
1208
|
-
`);
|
|
1209
|
-
const jobResult = await client.waitForJob(sendResult.jobId);
|
|
1210
|
-
const result = {
|
|
1211
|
-
...jobResult,
|
|
1212
|
-
explorer: explorerUrl(opts.chain, (sendResult.signature ?? jobResult.hash) || "")
|
|
1213
|
-
};
|
|
1214
|
-
printResult(result, opts.raw);
|
|
1215
|
-
} else {
|
|
1216
|
-
const result = {
|
|
1217
|
-
...sendResult,
|
|
1218
|
-
explorer: explorerUrl(opts.chain, sendResult.signature ?? "")
|
|
1219
|
-
};
|
|
1220
|
-
printResult(result, opts.raw);
|
|
1221
|
-
}
|
|
1268
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1222
1269
|
} catch (err) {
|
|
1223
1270
|
exitOnError(err);
|
|
1224
1271
|
}
|
|
1225
1272
|
});
|
|
1226
|
-
dex.command("create").description("
|
|
1273
|
+
dex.command("create").description("Build unsigned token creation transaction").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--from <address>", "Creator wallet address").requiredOption("--name <name>", "Token name").requiredOption("--symbol <symbol>", "Token symbol").option("--dex <dex>", "Launchpad: pumpfun/raydium", "pumpfun").option("--uri <uri>", "Metadata URI (IPFS/HTTP)").option("--image <url>", "Token image URL").action(async (opts, cmd) => {
|
|
1227
1274
|
try {
|
|
1228
1275
|
validateChain(opts.chain);
|
|
1229
|
-
|
|
1276
|
+
validateAddress(opts.from, opts.chain);
|
|
1277
|
+
const client = createClient();
|
|
1230
1278
|
const result = await callWithAutoPayment(
|
|
1231
1279
|
() => client.dex.createToken(opts.chain, {
|
|
1280
|
+
dex: opts.dex,
|
|
1281
|
+
userAddress: opts.from,
|
|
1232
1282
|
name: opts.name,
|
|
1233
1283
|
symbol: opts.symbol,
|
|
1234
1284
|
uri: opts.uri,
|
|
1235
|
-
|
|
1285
|
+
image: opts.image
|
|
1236
1286
|
})
|
|
1237
1287
|
);
|
|
1238
|
-
printResult(result,
|
|
1288
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1289
|
+
} catch (err) {
|
|
1290
|
+
exitOnError(err);
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// src/commands/transaction.ts
|
|
1296
|
+
var EVM_ONLY_CHAINS = /* @__PURE__ */ new Set(["eth", "bsc"]);
|
|
1297
|
+
function validateEvmChain(chain) {
|
|
1298
|
+
validateChain(chain);
|
|
1299
|
+
if (!EVM_ONLY_CHAINS.has(chain)) {
|
|
1300
|
+
throw new Error(`Chain "${chain}" is not supported for this operation. Only EVM chains: ${[...EVM_ONLY_CHAINS].join(", ")}`);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function registerTransactionCommands(program2) {
|
|
1304
|
+
const tx = program2.command("tx").description("Transaction broadcast, gas estimation");
|
|
1305
|
+
tx.command("send").description("Broadcast a signed transaction").requiredOption("--chain <chain>", "Chain: sol/bsc/eth").requiredOption("--signed-tx <base64>", "Base64-encoded signed transaction").option("--submit-type <type>", "Submit type: default/priority", "default").option("--anti-mev", "Enable anti-MEV protection").action(async (opts, cmd) => {
|
|
1306
|
+
try {
|
|
1307
|
+
validateChain(opts.chain);
|
|
1308
|
+
const client = createClient();
|
|
1309
|
+
const body = {
|
|
1310
|
+
signedTx: opts.signedTx
|
|
1311
|
+
};
|
|
1312
|
+
if (opts.submitType && opts.submitType !== "default") body.submitType = opts.submitType;
|
|
1313
|
+
if (opts.antiMev) body.options = { isAntiMev: true };
|
|
1314
|
+
const result = await callWithAutoPayment(
|
|
1315
|
+
() => client.transaction.send(opts.chain, body)
|
|
1316
|
+
);
|
|
1317
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1318
|
+
} catch (err) {
|
|
1319
|
+
exitOnError(err);
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
tx.command("gas-price").description("Get current gas price (EVM only)").requiredOption("--chain <chain>", "Chain: eth/bsc").action(async (opts, cmd) => {
|
|
1323
|
+
try {
|
|
1324
|
+
validateEvmChain(opts.chain);
|
|
1325
|
+
const client = createClient();
|
|
1326
|
+
const result = await callWithAutoPayment(
|
|
1327
|
+
() => client.transaction.getGasPrice(opts.chain)
|
|
1328
|
+
);
|
|
1329
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
exitOnError(err);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
tx.command("estimate-gas").description("Estimate gas limit for a transaction (EVM only)").requiredOption("--chain <chain>", "Chain: eth/bsc").requiredOption("--from <address>", "From address").requiredOption("--to <address>", "To address").requiredOption("--data <hex>", "Transaction data (hex)").option("--value <hex>", "Value in wei (hex string)", "0x0").action(async (opts, cmd) => {
|
|
1335
|
+
try {
|
|
1336
|
+
validateEvmChain(opts.chain);
|
|
1337
|
+
const client = createClient();
|
|
1338
|
+
const body = {
|
|
1339
|
+
from: opts.from,
|
|
1340
|
+
to: opts.to,
|
|
1341
|
+
data: opts.data
|
|
1342
|
+
};
|
|
1343
|
+
if (opts.value && opts.value !== "0x0") body.value = opts.value;
|
|
1344
|
+
const result = await callWithAutoPayment(
|
|
1345
|
+
() => client.transaction.getGasLimit(opts.chain, body)
|
|
1346
|
+
);
|
|
1347
|
+
printResult(result, cmd.optsWithGlobals().json);
|
|
1239
1348
|
} catch (err) {
|
|
1240
1349
|
exitOnError(err);
|
|
1241
1350
|
}
|
|
@@ -1245,8 +1354,9 @@ function registerDexCommands(program2) {
|
|
|
1245
1354
|
// src/commands/job.ts
|
|
1246
1355
|
function registerJobCommands(program2) {
|
|
1247
1356
|
const job = program2.command("job").description("Job status polling");
|
|
1248
|
-
job.command("status").description("Check job status").requiredOption("--id <jobId>", "Job ID").option("--wait", "Wait for job completion via SSE").option("--timeout <ms>", "Wait timeout in milliseconds", "60000").
|
|
1357
|
+
job.command("status").description("Check job status").requiredOption("--id <jobId>", "Job ID").option("--wait", "Wait for job completion via SSE").option("--timeout <ms>", "Wait timeout in milliseconds", "60000").action(async (opts, cmd) => {
|
|
1249
1358
|
try {
|
|
1359
|
+
const json = cmd.optsWithGlobals().json;
|
|
1250
1360
|
const client = createClient();
|
|
1251
1361
|
if (opts.wait) {
|
|
1252
1362
|
process.stderr.write(`Waiting for job ${opts.id}...
|
|
@@ -1254,12 +1364,12 @@ function registerJobCommands(program2) {
|
|
|
1254
1364
|
const result = await callWithAutoPayment(
|
|
1255
1365
|
() => client.waitForJob(opts.id, Number(opts.timeout))
|
|
1256
1366
|
);
|
|
1257
|
-
printResult(result,
|
|
1367
|
+
printResult(result, json);
|
|
1258
1368
|
} else {
|
|
1259
1369
|
const result = await callWithAutoPayment(
|
|
1260
1370
|
() => client.job.get(opts.id)
|
|
1261
1371
|
);
|
|
1262
|
-
printResult(result,
|
|
1372
|
+
printResult(result, json);
|
|
1263
1373
|
}
|
|
1264
1374
|
} catch (err) {
|
|
1265
1375
|
exitOnError(err);
|
|
@@ -1328,7 +1438,7 @@ function saveKey(keyPair, profile = DEFAULT_PROFILE) {
|
|
|
1328
1438
|
// src/commands/auth.ts
|
|
1329
1439
|
init_turnkey();
|
|
1330
1440
|
init_constants();
|
|
1331
|
-
import * as
|
|
1441
|
+
import * as readline3 from "readline/promises";
|
|
1332
1442
|
async function resolveAndStoreAddresses(turnkeyCreds) {
|
|
1333
1443
|
process.stderr.write("Resolving wallet addresses...\n");
|
|
1334
1444
|
const [evmAddress, solanaAddress] = await Promise.all([
|
|
@@ -1358,14 +1468,22 @@ function registerAuthCommands(program2) {
|
|
|
1358
1468
|
exitOnError(err);
|
|
1359
1469
|
}
|
|
1360
1470
|
});
|
|
1361
|
-
program2.command("logout").description("Clear session (P-256 keys preserved)").action(() => {
|
|
1471
|
+
program2.command("logout").description("Clear session (P-256 keys preserved)").action((_opts, cmd) => {
|
|
1472
|
+
const json = cmd.optsWithGlobals().json;
|
|
1362
1473
|
const config = loadConfig();
|
|
1363
|
-
|
|
1474
|
+
const wasLoggedIn = !!config.turnkey;
|
|
1475
|
+
if (wasLoggedIn) {
|
|
1364
1476
|
updateConfig({ turnkey: void 0 });
|
|
1365
|
-
|
|
1366
|
-
|
|
1477
|
+
}
|
|
1478
|
+
if (json) {
|
|
1479
|
+
printResult({ success: true, wasLoggedIn }, true);
|
|
1367
1480
|
} else {
|
|
1368
|
-
|
|
1481
|
+
if (wasLoggedIn) {
|
|
1482
|
+
process.stdout.write("Logged out. P-256 keys preserved in ~/.config/chainstream/keys/\n");
|
|
1483
|
+
process.stdout.write("Run 'chainstream login' to re-authenticate.\n");
|
|
1484
|
+
} else {
|
|
1485
|
+
process.stdout.write("Not logged in via Turnkey.\n");
|
|
1486
|
+
}
|
|
1369
1487
|
}
|
|
1370
1488
|
});
|
|
1371
1489
|
program2.command("bind-email").description("Bind an email to your wallet (for account recovery)").argument("[email]", "Email address to bind").action(async (emailArg) => {
|
|
@@ -1526,7 +1644,7 @@ async function doKeyLogin() {
|
|
|
1526
1644
|
}
|
|
1527
1645
|
async function doEmailLogin(email) {
|
|
1528
1646
|
if (!email) {
|
|
1529
|
-
const rl2 =
|
|
1647
|
+
const rl2 = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
1530
1648
|
email = await rl2.question("Enter your email: ");
|
|
1531
1649
|
rl2.close();
|
|
1532
1650
|
if (!email?.trim()) throw new Error("Email required.");
|
|
@@ -1542,7 +1660,7 @@ async function doEmailLogin(email) {
|
|
|
1542
1660
|
`);
|
|
1543
1661
|
return;
|
|
1544
1662
|
}
|
|
1545
|
-
const rl =
|
|
1663
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
1546
1664
|
const code = await rl.question("Enter OTP code: ");
|
|
1547
1665
|
rl.close();
|
|
1548
1666
|
if (!code?.trim()) throw new Error("OTP code required.");
|
|
@@ -1591,7 +1709,7 @@ async function doBindEmail(email) {
|
|
|
1591
1709
|
throw new Error("No wallet found. Run 'chainstream login' first.");
|
|
1592
1710
|
}
|
|
1593
1711
|
if (!email) {
|
|
1594
|
-
const rl2 =
|
|
1712
|
+
const rl2 = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
1595
1713
|
email = await rl2.question("Enter email to bind: ");
|
|
1596
1714
|
rl2.close();
|
|
1597
1715
|
if (!email?.trim()) throw new Error("Email required.");
|
|
@@ -1607,7 +1725,7 @@ async function doBindEmail(email) {
|
|
|
1607
1725
|
`);
|
|
1608
1726
|
return;
|
|
1609
1727
|
}
|
|
1610
|
-
const rl =
|
|
1728
|
+
const rl = readline3.createInterface({ input: process.stdin, output: process.stderr });
|
|
1611
1729
|
const code = await rl.question("Enter verification code: ");
|
|
1612
1730
|
rl.close();
|
|
1613
1731
|
if (!code?.trim()) throw new Error("Verification code required.");
|
|
@@ -1628,70 +1746,60 @@ async function doBindEmail(email) {
|
|
|
1628
1746
|
init_config();
|
|
1629
1747
|
function registerConfigCommands(program2) {
|
|
1630
1748
|
const config = program2.command("config").description("Configuration management");
|
|
1631
|
-
config.command("set").description("Set a configuration value").requiredOption("--key <key>", "Config key (apiKey, baseUrl)").requiredOption("--value <value>", "Config value").action((opts) => {
|
|
1749
|
+
config.command("set").description("Set a configuration value").requiredOption("--key <key>", "Config key (apiKey, baseUrl)").requiredOption("--value <value>", "Config value").action((opts, cmd) => {
|
|
1632
1750
|
try {
|
|
1751
|
+
const json = cmd.optsWithGlobals().json;
|
|
1633
1752
|
const allowedKeys = ["apiKey", "baseUrl", "walletChain"];
|
|
1634
1753
|
if (!allowedKeys.includes(opts.key)) {
|
|
1635
1754
|
throw new Error(`Invalid key "${opts.key}". Allowed: ${allowedKeys.join(", ")}`);
|
|
1636
1755
|
}
|
|
1637
1756
|
updateConfig({ [opts.key]: opts.value });
|
|
1638
|
-
|
|
1639
|
-
`);
|
|
1757
|
+
printResult({ key: opts.key, value: opts.key === "apiKey" ? "(set)" : opts.value }, json);
|
|
1640
1758
|
} catch (err) {
|
|
1641
1759
|
exitOnError(err);
|
|
1642
1760
|
}
|
|
1643
1761
|
});
|
|
1644
|
-
config.command("get").description("Show configuration").option("--key <key>", "Specific key to show").action((opts) => {
|
|
1762
|
+
config.command("get").description("Show configuration").option("--key <key>", "Specific key to show").action((opts, cmd) => {
|
|
1645
1763
|
try {
|
|
1764
|
+
const json = cmd.optsWithGlobals().json;
|
|
1646
1765
|
const cfg = loadConfig();
|
|
1647
1766
|
if (opts.key) {
|
|
1648
1767
|
const value = cfg[opts.key];
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
`);
|
|
1652
|
-
} else if (opts.key === "apiKey" && typeof value === "string") {
|
|
1653
|
-
process.stdout.write(`${opts.key}: ${value.slice(0, 8)}...${value.slice(-4)}
|
|
1654
|
-
`);
|
|
1655
|
-
} else {
|
|
1656
|
-
process.stdout.write(`${opts.key}: ${JSON.stringify(value)}
|
|
1657
|
-
`);
|
|
1658
|
-
}
|
|
1768
|
+
const displayValue = value === void 0 ? null : opts.key === "apiKey" && typeof value === "string" ? `${value.slice(0, 8)}...${value.slice(-4)}` : value;
|
|
1769
|
+
printResult({ key: opts.key, value: displayValue }, json);
|
|
1659
1770
|
} else {
|
|
1660
1771
|
const display = {
|
|
1661
|
-
apiKey: cfg.apiKey ? `${cfg.apiKey.slice(0, 8)}...` :
|
|
1772
|
+
apiKey: cfg.apiKey ? `${cfg.apiKey.slice(0, 8)}...` : null,
|
|
1662
1773
|
baseUrl: cfg.baseUrl,
|
|
1663
|
-
walletMode: getWalletMode(cfg),
|
|
1664
|
-
|
|
1665
|
-
rawWallet: cfg.rawWallet ? { chain: cfg.rawWallet.chain } : void 0
|
|
1774
|
+
walletMode: getWalletMode(cfg) ?? null,
|
|
1775
|
+
walletChain: cfg.walletChain ?? null
|
|
1666
1776
|
};
|
|
1667
|
-
|
|
1777
|
+
printResult(display, json);
|
|
1668
1778
|
}
|
|
1669
1779
|
} catch (err) {
|
|
1670
1780
|
exitOnError(err);
|
|
1671
1781
|
}
|
|
1672
1782
|
});
|
|
1673
|
-
config.command("auth").description("Show current authentication status").action(() => {
|
|
1783
|
+
config.command("auth").description("Show current authentication status").action((_opts, cmd) => {
|
|
1674
1784
|
try {
|
|
1785
|
+
const json = cmd.optsWithGlobals().json;
|
|
1675
1786
|
const cfg = loadConfig();
|
|
1676
1787
|
const mode = getWalletMode(cfg);
|
|
1788
|
+
const status = { mode: mode ?? "none" };
|
|
1677
1789
|
if (mode === "turnkey") {
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1790
|
+
status.organizationId = cfg.turnkey.organizationId;
|
|
1791
|
+
status.evmAddress = cfg.turnkey.evmAddress ?? null;
|
|
1792
|
+
status.solanaAddress = cfg.turnkey.solanaAddress ?? null;
|
|
1681
1793
|
const expired = Date.now() > cfg.turnkey.sessionExpiry * 1e3;
|
|
1682
|
-
|
|
1683
|
-
|
|
1794
|
+
status.session = expired ? "expired" : "active";
|
|
1795
|
+
status.sessionExpiry = new Date(cfg.turnkey.sessionExpiry * 1e3).toISOString();
|
|
1684
1796
|
} else if (mode === "raw") {
|
|
1685
|
-
|
|
1686
|
-
`);
|
|
1797
|
+
status.chain = cfg.rawWallet.chain;
|
|
1687
1798
|
} else if (cfg.apiKey) {
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
} else {
|
|
1691
|
-
process.stdout.write("Auth: Not configured\n");
|
|
1692
|
-
process.stdout.write(" Run: chainstream login # Turnkey wallet\n");
|
|
1693
|
-
process.stdout.write(" Run: chainstream config set --key apiKey --value <key> # API key\n");
|
|
1799
|
+
status.mode = "apiKey";
|
|
1800
|
+
status.apiKey = `${cfg.apiKey.slice(0, 8)}...`;
|
|
1694
1801
|
}
|
|
1802
|
+
printResult(status, json);
|
|
1695
1803
|
} catch (err) {
|
|
1696
1804
|
exitOnError(err);
|
|
1697
1805
|
}
|
|
@@ -1700,11 +1808,12 @@ function registerConfigCommands(program2) {
|
|
|
1700
1808
|
|
|
1701
1809
|
// src/index.ts
|
|
1702
1810
|
var program = new Command();
|
|
1703
|
-
program.name("chainstream").version("0.
|
|
1811
|
+
program.name("chainstream").version("0.0.19").description("ChainStream CLI \u2014 on-chain data and DeFi execution for AI agents").option("--json", "Output as single-line JSON (machine-readable)");
|
|
1704
1812
|
registerTokenCommands(program);
|
|
1705
1813
|
registerMarketCommands(program);
|
|
1706
1814
|
registerWalletCommands(program);
|
|
1707
1815
|
registerDexCommands(program);
|
|
1816
|
+
registerTransactionCommands(program);
|
|
1708
1817
|
registerJobCommands(program);
|
|
1709
1818
|
registerAuthCommands(program);
|
|
1710
1819
|
registerConfigCommands(program);
|