Last active
May 8, 2025 12:00
-
-
Save rollendxavier/ddf88a408cba5abbe9025ce9d9b07b6f to your computer and use it in GitHub Desktop.
This command-line tool lets you interact with CoinGecko Pro API using the Goat SDK.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* GoatGecko SDK CLI | |
* | |
* This command-line tool lets you interact with CoinGecko Pro API using the Goat SDK. | |
* Features: | |
* - Coin historical data | |
* - OHLC data | |
* - Trending coins | |
* - Trending pools by network | |
* - Top gainers & losers | |
* | |
* Usage: | |
* - Make sure you have a .env file with COINGECKO_API_KEY set. | |
* - Run: npm start or node dist/index.js | |
*/ | |
import { coingecko } from "@goat-sdk/plugin-coingecko"; | |
import { getTools } from "@goat-sdk/core"; | |
import dotenv from "dotenv"; | |
import { CoinGeckoTools } from "./cg-tools.enum.js"; | |
import inquirer from "inquirer"; | |
dotenv.config(); | |
// Validate environment variables | |
if (!process.env.COINGECKO_API_KEY) { | |
console.error("[ERROR] COINGECKO_API_KEY is missing in the .env file."); | |
process.exit(1); | |
} | |
const wallet = { | |
getChain: () => ({ | |
id: 1, | |
name: "Ethereum", | |
rpcUrls: [], | |
type: "radix" as const, | |
}), | |
getAccounts: () => [ | |
{ | |
address: "0x0", | |
balance: { | |
amount: "0", | |
decimals: 18, | |
symbol: "ETH", | |
name: "Ether", | |
value: "0", | |
inBaseUnits: "0", | |
}, | |
}, | |
], | |
signMessage: async () => ({ signature: "stub" }), | |
getAddress: () => "0x0", | |
balanceOf: async () => ({ | |
amount: "0", | |
decimals: 18, | |
symbol: "ETH", | |
name: "Ether", | |
value: "0", | |
inBaseUnits: "0", | |
}), | |
getCoreTools: () => [], | |
}; | |
// Utility function to validate inputs | |
function validateInput(input: string, fieldName: string): string { | |
if (!input || input.trim() === "") { | |
throw new Error(`[ERROR] ${fieldName} cannot be empty.`); | |
} | |
return input.trim(); | |
} | |
function getToolByEnum(tools: any[], name: CoinGeckoTools) { | |
return tools.find(tool => tool.name === name); | |
} | |
async function main() { | |
try { | |
const tools = await getTools({ | |
wallet, | |
plugins: [ | |
coingecko({ | |
apiKey: process.env.COINGECKO_API_KEY || "", | |
isPro: true, | |
}), | |
], | |
}); | |
const getHistoricalData = getToolByEnum(tools, CoinGeckoTools.GetHistoricalData); | |
const getOHLCData = getToolByEnum(tools, CoinGeckoTools.GetOHLCData); | |
const getTrendingCoins = getToolByEnum(tools, CoinGeckoTools.GetTrendingCoins); | |
const getTrendingPoolsByNetwork = getToolByEnum(tools, CoinGeckoTools.GetTrendingPoolsByNetwork); | |
const getTopGainersLosers = getToolByEnum(tools, CoinGeckoTools.GetTopGainersLosers); | |
if (!getHistoricalData || !getOHLCData || !getTrendingCoins || !getTrendingPoolsByNetwork || !getTopGainersLosers) { | |
throw new Error("[ERROR] Required CoinGecko tools not found."); | |
} | |
while (true) { | |
const { action } = await inquirer.prompt([ | |
{ | |
type: "list", | |
name: "action", | |
message: "Select an action:", | |
choices: [ | |
{ name: "Coin Historical Data", value: "historical" }, | |
{ name: "OHLC Data", value: "ohlc" }, | |
{ name: "Trending Coins", value: "trending" }, | |
{ name: "Trending Pools by Network", value: "pools" }, | |
{ name: "Top Gainers & Losers", value: "gainers_losers" }, | |
{ name: "Exit", value: "exit" } | |
] | |
} | |
]); | |
if (action === "exit") { | |
console.log("Goodbye!"); | |
break; | |
} | |
try { | |
switch (action) { | |
case "historical": { | |
const { id, date } = await inquirer.prompt<{ | |
id: string; | |
date: string; | |
}>([ | |
{ type: "input", name: "id", message: "Coin ID (e.g. bitcoin):", default: "bitcoin" }, | |
{ type: "input", name: "date", message: "Date (DD-MM-YYYY):", default: "30-12-2021" } | |
]); | |
const validatedId = validateInput(id, "Coin ID"); | |
const validatedDate = validateInput(date, "Date"); | |
const result = await getHistoricalData.execute({ id: validatedId, date: validatedDate, localization: false }); | |
console.log("\n=== Historical Data ==="); | |
console.dir(result, { depth: null, colors: true }); | |
break; | |
} | |
case "ohlc": { | |
const { id, vsCurrency, days } = await inquirer.prompt<{ | |
id: string; | |
vsCurrency: string; | |
days: string; | |
}>([ | |
{ type: "input", name: "id", message: "Coin ID (e.g. bitcoin):", default: "bitcoin" }, | |
{ type: "input", name: "vsCurrency", message: "VS Currency (e.g. usd):", default: "usd" }, | |
{ type: "input", name: "days", message: "Days (e.g. 7):", default: "7" } | |
]); | |
const validatedId = validateInput(id, "Coin ID"); | |
const validatedCurrency = validateInput(vsCurrency, "VS Currency"); | |
const validatedDays = parseInt(days, 10); | |
if (isNaN(validatedDays) || validatedDays <= 0) { | |
throw new Error("[ERROR] Days must be a positive number."); | |
} | |
const result = await getOHLCData.execute({ id: validatedId, vsCurrency: validatedCurrency, days: validatedDays }); | |
console.log("\n=== OHLC Data ==="); | |
console.dir(result, { depth: null, colors: true }); | |
break; | |
} | |
case "trending": { | |
const result = await getTrendingCoins.execute({}); | |
console.log("\n=== Trending Coins ==="); | |
console.dir(result, { depth: null, colors: true }); | |
break; | |
} | |
case "pools": { | |
const { network } = await inquirer.prompt<{ | |
network: string; | |
}>([ | |
{ type: "input", name: "network", message: "Network (e.g. eth):", default: "eth" } | |
]); | |
const validatedNetwork = validateInput(network, "Network"); | |
const result = await getTrendingPoolsByNetwork.execute({ network: validatedNetwork }); | |
console.log(`\n=== Trending Pools on ${validatedNetwork} ===`); | |
console.dir(result, { depth: null, colors: true }); | |
break; | |
} | |
case "gainers_losers": { | |
const { vsCurrency, perPage, page } = await inquirer.prompt<{ | |
vsCurrency: string; | |
perPage: string; | |
page: string; | |
}>([ | |
{ type: "input", name: "vsCurrency", message: "VS Currency (e.g. usd):", default: "usd" }, | |
{ type: "input", name: "perPage", message: "Results per page:", default: "10" }, | |
{ type: "input", name: "page", message: "Page number:", default: "1" } | |
]); | |
const validatedCurrency = validateInput(vsCurrency, "VS Currency"); | |
const validatedPerPage = parseInt(perPage, 10); | |
const validatedPage = parseInt(page, 10); | |
if (isNaN(validatedPerPage) || validatedPerPage <= 0 || isNaN(validatedPage) || validatedPage <= 0) { | |
throw new Error("[ERROR] Per page and page number must be positive numbers."); | |
} | |
const result = await getTopGainersLosers.execute({ | |
vsCurrency: validatedCurrency, | |
perPage: validatedPerPage, | |
page: validatedPage, | |
}); | |
console.log("\n=== Top Gainers & Losers ==="); | |
console.dir(result, { depth: null, colors: true }); | |
break; | |
} | |
} | |
} catch (err: any) { | |
console.error("\n[!] Error:", err.message); | |
} | |
console.log("\n----------------------------------------\n"); | |
} | |
} catch (err: any) { | |
console.error("[FATAL] Startup error:", err.message); | |
process.exit(1); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment