@covalenthq/goldrush-cli 3.0.1 → 3.0.2
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 +170 -51
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@covalenthq/goldrush-cli",
|
|
6
|
-
version: "3.0.
|
|
6
|
+
version: "3.0.2",
|
|
7
7
|
description: "Terminal-first blockchain data & algorithmic trading CLI powered by GoldRush API",
|
|
8
8
|
type: "module",
|
|
9
9
|
bin: {
|
|
@@ -45,8 +45,8 @@ var package_default = {
|
|
|
45
45
|
homepage: "https://goldrush.dev/docs/",
|
|
46
46
|
repository: {
|
|
47
47
|
type: "git",
|
|
48
|
-
url: "https://github.com/covalenthq/
|
|
49
|
-
directory: "services/
|
|
48
|
+
url: "https://github.com/covalenthq/goldrush-services-monorepo.git",
|
|
49
|
+
directory: "services/goldrush-cli"
|
|
50
50
|
},
|
|
51
51
|
dependencies: {
|
|
52
52
|
"@covalenthq/client-sdk": "workspace:^",
|
|
@@ -100,6 +100,9 @@ async function getKeytar() {
|
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
async function isKeychainAvailable() {
|
|
104
|
+
return await getKeytar() !== null;
|
|
105
|
+
}
|
|
103
106
|
async function getApiKey() {
|
|
104
107
|
const keytar = await getKeytar();
|
|
105
108
|
if (keytar) {
|
|
@@ -186,10 +189,7 @@ import { GoldRushClient } from "@covalenthq/client-sdk";
|
|
|
186
189
|
async function validateApiKey(key) {
|
|
187
190
|
try {
|
|
188
191
|
const client = new GoldRushClient(key);
|
|
189
|
-
const response = await client.
|
|
190
|
-
"eth-mainnet",
|
|
191
|
-
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
|
|
192
|
-
);
|
|
192
|
+
const response = await client.BaseService.getAllChains();
|
|
193
193
|
if (response.error) {
|
|
194
194
|
return {
|
|
195
195
|
valid: false,
|
|
@@ -242,6 +242,14 @@ function infoBox(title, message) {
|
|
|
242
242
|
borderStyle: "round"
|
|
243
243
|
});
|
|
244
244
|
}
|
|
245
|
+
function warningBox(title, message) {
|
|
246
|
+
return boxen(message, {
|
|
247
|
+
title: chalk.hex("#FFE66D").bold(title),
|
|
248
|
+
borderColor: "yellow",
|
|
249
|
+
padding: 1,
|
|
250
|
+
borderStyle: "round"
|
|
251
|
+
});
|
|
252
|
+
}
|
|
245
253
|
|
|
246
254
|
// src/ui/spinner.ts
|
|
247
255
|
import ora from "ora";
|
|
@@ -299,14 +307,34 @@ var authCommand = new Command("auth").description("Set up your GoldRush API key"
|
|
|
299
307
|
const result = await validateApiKey(apiKey.trim());
|
|
300
308
|
if (result.valid) {
|
|
301
309
|
await setApiKey(apiKey.trim());
|
|
310
|
+
const keychainAvailable = await isKeychainAvailable();
|
|
302
311
|
spinner.succeed("API key validated and stored securely");
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
312
|
+
if (keychainAvailable) {
|
|
313
|
+
console.log(
|
|
314
|
+
successBox(
|
|
315
|
+
"Authentication Complete",
|
|
316
|
+
`API key stored in OS keychain
|
|
307
317
|
Key: ${colors.gold(apiKey.trim().slice(0, 6) + "..." + apiKey.trim().slice(-4))}`
|
|
308
|
-
|
|
309
|
-
|
|
318
|
+
)
|
|
319
|
+
);
|
|
320
|
+
} else {
|
|
321
|
+
console.log(
|
|
322
|
+
successBox(
|
|
323
|
+
"Authentication Complete",
|
|
324
|
+
`Key: ${colors.gold(apiKey.trim().slice(0, 6) + "..." + apiKey.trim().slice(-4))}`
|
|
325
|
+
)
|
|
326
|
+
);
|
|
327
|
+
console.log(
|
|
328
|
+
warningBox(
|
|
329
|
+
"Plaintext Storage Warning",
|
|
330
|
+
`The OS keychain (keytar) is not available on this system.
|
|
331
|
+
Your API key is stored in plaintext in the local config file.
|
|
332
|
+
|
|
333
|
+
To use secure storage, install the keytar native module or set
|
|
334
|
+
the ${colors.accent("GOLDRUSH_API_KEY")} environment variable instead.`
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
}
|
|
310
338
|
} else {
|
|
311
339
|
spinner.fail("Invalid API key");
|
|
312
340
|
console.log(
|
|
@@ -4961,9 +4989,15 @@ var gasCommand = new Command5("gas").description("Get real-time gas price estima
|
|
|
4961
4989
|
if (!eventType) {
|
|
4962
4990
|
console.log(
|
|
4963
4991
|
errorBox(
|
|
4964
|
-
"Invalid Type",
|
|
4965
|
-
`
|
|
4966
|
-
|
|
4992
|
+
"Invalid Transaction Type",
|
|
4993
|
+
`"${colors.accent(options.type)}" is not a valid transaction type.
|
|
4994
|
+
|
|
4995
|
+
Valid values:
|
|
4996
|
+
${colors.gold("erc20")} \u2014 ERC-20 token transfer gas estimates
|
|
4997
|
+
${colors.gold("native")} \u2014 Native token transfer gas estimates
|
|
4998
|
+
${colors.gold("swap")} \u2014 Uniswap v3 swap gas estimates
|
|
4999
|
+
|
|
5000
|
+
Example: ${colors.accent(`goldrush gas eth-mainnet --type swap`)}`
|
|
4967
5001
|
)
|
|
4968
5002
|
);
|
|
4969
5003
|
return;
|
|
@@ -5580,7 +5614,6 @@ async function subscribeToWalletActivity(chainName, walletAddresses, callback) {
|
|
|
5580
5614
|
},
|
|
5581
5615
|
{
|
|
5582
5616
|
next: (events) => {
|
|
5583
|
-
infoBox(JSON.stringify(events, null, 2), "Wallet Activity");
|
|
5584
5617
|
for (const event of events) {
|
|
5585
5618
|
const decodedType = parseDecodedType(event.decoded_type);
|
|
5586
5619
|
const { summary, quoteUsd, tokenSymbol } = buildDetailsSummary(decodedType, event.decoded_details);
|
|
@@ -5615,9 +5648,39 @@ async function subscribeToWalletActivity(chainName, walletAddresses, callback) {
|
|
|
5615
5648
|
return unsubscribe;
|
|
5616
5649
|
}
|
|
5617
5650
|
|
|
5651
|
+
// src/utils/clipboard.ts
|
|
5652
|
+
import { execSync } from "child_process";
|
|
5653
|
+
function copyToClipboard(text) {
|
|
5654
|
+
const platform = process.platform;
|
|
5655
|
+
try {
|
|
5656
|
+
if (platform === "darwin") {
|
|
5657
|
+
execSync("pbcopy", { input: text });
|
|
5658
|
+
return true;
|
|
5659
|
+
}
|
|
5660
|
+
if (platform === "win32") {
|
|
5661
|
+
execSync(
|
|
5662
|
+
`powershell -NoProfile -Command "$input | Set-Clipboard"`,
|
|
5663
|
+
{ input: text }
|
|
5664
|
+
);
|
|
5665
|
+
return true;
|
|
5666
|
+
}
|
|
5667
|
+
if (platform === "linux") {
|
|
5668
|
+
try {
|
|
5669
|
+
execSync("xclip -selection clipboard", { input: text });
|
|
5670
|
+
return true;
|
|
5671
|
+
} catch {
|
|
5672
|
+
execSync("xsel --clipboard --input", { input: text });
|
|
5673
|
+
return true;
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
return false;
|
|
5677
|
+
} catch {
|
|
5678
|
+
return false;
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5681
|
+
|
|
5618
5682
|
// src/commands/newpairs.ts
|
|
5619
5683
|
import { Command as Command9 } from "commander";
|
|
5620
|
-
import { execSync } from "child_process";
|
|
5621
5684
|
var newpairsCommand = new Command9("new_pairs").description("Fetch the latest new DEX liquidity pairs").argument("[chain]", "Blockchain name (e.g. eth-mainnet)").argument(
|
|
5622
5685
|
"[protocols...]",
|
|
5623
5686
|
"Filter by DEX protocol(s) (e.g. uniswap-v2 raydium-amm)"
|
|
@@ -5715,14 +5778,6 @@ Supported protocols:
|
|
|
5715
5778
|
function getPairsArray() {
|
|
5716
5779
|
return [...pairMap.values()].reverse().slice(0, limit);
|
|
5717
5780
|
}
|
|
5718
|
-
function copyToClipboard(text) {
|
|
5719
|
-
try {
|
|
5720
|
-
execSync("pbcopy", { input: text });
|
|
5721
|
-
return true;
|
|
5722
|
-
} catch {
|
|
5723
|
-
return false;
|
|
5724
|
-
}
|
|
5725
|
-
}
|
|
5726
5781
|
function rerender() {
|
|
5727
5782
|
const pairs = getPairsArray();
|
|
5728
5783
|
if (selectedRow >= pairs.length) {
|
|
@@ -6184,12 +6239,19 @@ var asciiArt = [
|
|
|
6184
6239
|
" \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Terminal-first blockchain data & trading \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",
|
|
6185
6240
|
" \u2550\u2550\u2550\u2550\u2550\u2550 powered by Covalent \u2550\u2550\u2550\u2550\u2550\u2550"
|
|
6186
6241
|
];
|
|
6187
|
-
function printLogo() {
|
|
6242
|
+
function printLogo(version) {
|
|
6188
6243
|
console.log();
|
|
6189
6244
|
for (let i = 0; i < asciiArt.length; i++) {
|
|
6190
6245
|
const colorIdx = Math.min(i, gradientStops.length - 1);
|
|
6191
6246
|
console.log(chalk5.hex(gradientStops[colorIdx])(asciiArt[i]));
|
|
6192
6247
|
}
|
|
6248
|
+
if (version) {
|
|
6249
|
+
console.log(
|
|
6250
|
+
chalk5.hex(gradientStops[gradientStops.length - 1])(
|
|
6251
|
+
` v${version}`
|
|
6252
|
+
)
|
|
6253
|
+
);
|
|
6254
|
+
}
|
|
6193
6255
|
console.log();
|
|
6194
6256
|
}
|
|
6195
6257
|
|
|
@@ -6413,8 +6475,11 @@ async function startProxyServer(port) {
|
|
|
6413
6475
|
);
|
|
6414
6476
|
process.exit(1);
|
|
6415
6477
|
}
|
|
6416
|
-
|
|
6417
|
-
|
|
6478
|
+
let sessionToken = await getSessionToken();
|
|
6479
|
+
if (!sessionToken) {
|
|
6480
|
+
sessionToken = crypto.randomBytes(32).toString("hex");
|
|
6481
|
+
await setSessionToken(sessionToken);
|
|
6482
|
+
}
|
|
6418
6483
|
const app = express();
|
|
6419
6484
|
app.use(express.json());
|
|
6420
6485
|
app.use(bodySizeLimit);
|
|
@@ -6424,7 +6489,7 @@ async function startProxyServer(port) {
|
|
|
6424
6489
|
app.get("/tools", toolsHandler);
|
|
6425
6490
|
app.post("/call", callHandler);
|
|
6426
6491
|
const server = app.listen(serverPort, () => {
|
|
6427
|
-
printLogo();
|
|
6492
|
+
printLogo(package_default.version);
|
|
6428
6493
|
console.log(
|
|
6429
6494
|
successBox(
|
|
6430
6495
|
"Proxy Server Running",
|
|
@@ -6461,11 +6526,19 @@ var proxyCommand = new Command11("proxy").description("Launch the GoldRush proxy
|
|
|
6461
6526
|
});
|
|
6462
6527
|
|
|
6463
6528
|
// src/api/search.ts
|
|
6529
|
+
var SearchTimeoutError = class extends Error {
|
|
6530
|
+
constructor() {
|
|
6531
|
+
super(
|
|
6532
|
+
"Search request timed out. The streaming service did not respond within 15 seconds."
|
|
6533
|
+
);
|
|
6534
|
+
this.name = "SearchTimeoutError";
|
|
6535
|
+
}
|
|
6536
|
+
};
|
|
6464
6537
|
var SEARCH_TOKEN_QUERY = `
|
|
6465
6538
|
query SearchToken($query: String!) {
|
|
6466
6539
|
searchToken(query: $query) {
|
|
6467
6540
|
pair_address
|
|
6468
|
-
|
|
6541
|
+
chain_name
|
|
6469
6542
|
quote_rate
|
|
6470
6543
|
quote_rate_usd
|
|
6471
6544
|
volume
|
|
@@ -6493,11 +6566,11 @@ async function searchTokens(query) {
|
|
|
6493
6566
|
{ query },
|
|
6494
6567
|
{
|
|
6495
6568
|
next: (data) => {
|
|
6496
|
-
const items = data?.searchToken ?? data ??
|
|
6569
|
+
const items = data?.data?.searchToken ?? data?.searchToken ?? data;
|
|
6497
6570
|
const list = Array.isArray(items) ? items : [];
|
|
6498
6571
|
results = list.map((item) => ({
|
|
6499
6572
|
pairAddress: item.pair_address ?? "",
|
|
6500
|
-
chain: item.chain ?? "",
|
|
6573
|
+
chain: item.chain_name ?? item.chain ?? "",
|
|
6501
6574
|
quoteRate: item.quote_rate ?? 0,
|
|
6502
6575
|
quoteRateUsd: item.quote_rate_usd ?? 0,
|
|
6503
6576
|
volume: item.volume ?? 0,
|
|
@@ -6524,7 +6597,13 @@ async function searchTokens(query) {
|
|
|
6524
6597
|
}
|
|
6525
6598
|
}
|
|
6526
6599
|
);
|
|
6527
|
-
setTimeout(() =>
|
|
6600
|
+
setTimeout(() => {
|
|
6601
|
+
if (results.length === 0) {
|
|
6602
|
+
reject(new SearchTimeoutError());
|
|
6603
|
+
} else {
|
|
6604
|
+
resolve2(results);
|
|
6605
|
+
}
|
|
6606
|
+
}, 15e3);
|
|
6528
6607
|
});
|
|
6529
6608
|
}
|
|
6530
6609
|
|
|
@@ -6573,8 +6652,21 @@ Results: ${colors.gold(String(results.length))} (sorted by volume)`
|
|
|
6573
6652
|
);
|
|
6574
6653
|
renderSearchResultsTable(results);
|
|
6575
6654
|
} catch (err) {
|
|
6576
|
-
|
|
6577
|
-
|
|
6655
|
+
if (err instanceof SearchTimeoutError) {
|
|
6656
|
+
spinner.warn("Request timed out");
|
|
6657
|
+
console.log(
|
|
6658
|
+
warningBox(
|
|
6659
|
+
"Search Timed Out",
|
|
6660
|
+
`No response from the streaming service within 15 seconds.
|
|
6661
|
+
|
|
6662
|
+
Try again or check your connection.
|
|
6663
|
+
Run ${colors.accent("goldrush status")} to verify your API key.`
|
|
6664
|
+
)
|
|
6665
|
+
);
|
|
6666
|
+
} else {
|
|
6667
|
+
spinner.fail("Search failed");
|
|
6668
|
+
console.log(errorBox("Error", err.message));
|
|
6669
|
+
}
|
|
6578
6670
|
}
|
|
6579
6671
|
});
|
|
6580
6672
|
|
|
@@ -6632,6 +6724,14 @@ Proxy Port: ${colors.accent(String(port))}`
|
|
|
6632
6724
|
});
|
|
6633
6725
|
|
|
6634
6726
|
// src/api/traders.ts
|
|
6727
|
+
var TradersTimeoutError = class extends Error {
|
|
6728
|
+
constructor() {
|
|
6729
|
+
super(
|
|
6730
|
+
"Traders request timed out. The streaming service did not respond within 15 seconds."
|
|
6731
|
+
);
|
|
6732
|
+
this.name = "TradersTimeoutError";
|
|
6733
|
+
}
|
|
6734
|
+
};
|
|
6635
6735
|
var UPNL_FOR_TOKEN_QUERY = `
|
|
6636
6736
|
query UpnlForToken($chain_name: ChainName!, $token_address: String!) {
|
|
6637
6737
|
upnlForToken(chain_name: $chain_name, token_address: $token_address) {
|
|
@@ -6691,7 +6791,13 @@ async function getTopTraders(chainName, tokenAddress) {
|
|
|
6691
6791
|
}
|
|
6692
6792
|
}
|
|
6693
6793
|
);
|
|
6694
|
-
setTimeout(() =>
|
|
6794
|
+
setTimeout(() => {
|
|
6795
|
+
if (results.length === 0) {
|
|
6796
|
+
reject(new TradersTimeoutError());
|
|
6797
|
+
} else {
|
|
6798
|
+
resolve2(results);
|
|
6799
|
+
}
|
|
6800
|
+
}, 15e3);
|
|
6695
6801
|
});
|
|
6696
6802
|
}
|
|
6697
6803
|
|
|
@@ -6758,8 +6864,21 @@ Traders: ${colors.gold(String(traders.length))}`
|
|
|
6758
6864
|
);
|
|
6759
6865
|
renderTopTradersTable(traders);
|
|
6760
6866
|
} catch (err) {
|
|
6761
|
-
|
|
6762
|
-
|
|
6867
|
+
if (err instanceof TradersTimeoutError) {
|
|
6868
|
+
spinner.warn("Request timed out");
|
|
6869
|
+
console.log(
|
|
6870
|
+
warningBox(
|
|
6871
|
+
"Traders Query Timed Out",
|
|
6872
|
+
`No response from the streaming service within 15 seconds.
|
|
6873
|
+
|
|
6874
|
+
Make sure the token address is on a supported streaming chain.
|
|
6875
|
+
Run ${colors.accent("goldrush status")} to verify your API key.`
|
|
6876
|
+
)
|
|
6877
|
+
);
|
|
6878
|
+
} else {
|
|
6879
|
+
spinner.fail("Failed to fetch top traders");
|
|
6880
|
+
console.log(errorBox("Error", err.message));
|
|
6881
|
+
}
|
|
6763
6882
|
}
|
|
6764
6883
|
}
|
|
6765
6884
|
);
|
|
@@ -6861,7 +6980,6 @@ Showing: ${colors.gold(String(transfers.length))} most recent`
|
|
|
6861
6980
|
// src/commands/watch.ts
|
|
6862
6981
|
import { input as input7 } from "@inquirer/prompts";
|
|
6863
6982
|
import { Command as Command16 } from "commander";
|
|
6864
|
-
import { execSync as execSync2 } from "child_process";
|
|
6865
6983
|
var watchCommand = new Command16("watch").description("Stream live wallet activity (transactions, transfers, swaps)").argument("[address]", "Wallet address to watch").argument("[chain]", "Blockchain name (e.g. eth-mainnet)").option("-l, --limit <number>", "Max rows to display", "20").action(
|
|
6866
6984
|
async (address, chain, opts) => {
|
|
6867
6985
|
if (!await isAuthenticated()) {
|
|
@@ -6876,8 +6994,17 @@ var watchCommand = new Command16("watch").description("Stream live wallet activi
|
|
|
6876
6994
|
let walletAddress = address;
|
|
6877
6995
|
if (!walletAddress) {
|
|
6878
6996
|
walletAddress = await input7({
|
|
6879
|
-
message: colors.primary(
|
|
6880
|
-
|
|
6997
|
+
message: colors.primary(
|
|
6998
|
+
"Wallet address or ENS name to watch:"
|
|
6999
|
+
),
|
|
7000
|
+
validate: (val) => {
|
|
7001
|
+
const v = val.trim();
|
|
7002
|
+
if (!v) return "Please enter an address or ENS name.";
|
|
7003
|
+
if (/^0x[a-fA-F0-9]{40}$/.test(v) || /^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.eth$/.test(v)) {
|
|
7004
|
+
return true;
|
|
7005
|
+
}
|
|
7006
|
+
return "Enter a valid EVM address (0x\u202640 hex chars) or ENS name (e.g. vitalik.eth).";
|
|
7007
|
+
}
|
|
6881
7008
|
});
|
|
6882
7009
|
walletAddress = walletAddress.trim();
|
|
6883
7010
|
}
|
|
@@ -6942,14 +7069,6 @@ Run ${colors.accent("goldrush chains")} for details.`
|
|
|
6942
7069
|
function getDisplayActivities() {
|
|
6943
7070
|
return activities.slice(0, limit);
|
|
6944
7071
|
}
|
|
6945
|
-
function copyToClipboard(text) {
|
|
6946
|
-
try {
|
|
6947
|
-
execSync2("pbcopy", { input: text });
|
|
6948
|
-
return true;
|
|
6949
|
-
} catch {
|
|
6950
|
-
return false;
|
|
6951
|
-
}
|
|
6952
|
-
}
|
|
6953
7072
|
function rerender() {
|
|
6954
7073
|
const display = getDisplayActivities();
|
|
6955
7074
|
if (selectedRow >= display.length) {
|
|
@@ -7121,7 +7240,7 @@ program.addCommand(mcpCommand);
|
|
|
7121
7240
|
program.addCommand(chainsCommand);
|
|
7122
7241
|
program.addCommand(watchCommand);
|
|
7123
7242
|
program.action(async () => {
|
|
7124
|
-
printLogo();
|
|
7243
|
+
printLogo(package_default.version);
|
|
7125
7244
|
const action = await select3({
|
|
7126
7245
|
message: colors.primary("What would you like to do?"),
|
|
7127
7246
|
choices: [
|