@tamago-labs/cronos-mcp
Version:
MCP server for Cronos Web3 Analytics - comprehensive blockchain analytics for Cronos and zkEVM networks with VVS Finance DEX integration
1,326 lines (1,313 loc) • 58.1 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// src/config.ts
var import_developer_platform_client = require("@crypto.com/developer-platform-client");
var NETWORK_CONFIGS = {
"cronos-mainnet": {
name: "Cronos Mainnet",
chain: import_developer_platform_client.CronosEvm.Mainnet,
rpcUrl: "https://evm.cronos.org",
blockExplorer: "https://cronoscan.com",
nativeCurrency: "CRO",
apiKeyRequired: true
},
"cronos-zkevm-mainnet": {
name: "Cronos zkEVM Mainnet",
chain: import_developer_platform_client.CronosZkEvm.Mainnet,
rpcUrl: "https://mainnet.zkevm.cronos.org",
blockExplorer: "https://explorer.zkevm.cronos.org",
nativeCurrency: "zkCRO",
apiKeyRequired: true
}
};
var getArgs = () => process.argv.reduce((args, arg) => {
if (arg.slice(0, 2) === "--") {
const longArg = arg.split("=");
const longArgFlag = longArg[0].slice(2);
const longArgValue = longArg.length > 1 ? longArg[1] : true;
args[longArgFlag] = longArgValue;
} else if (arg[0] === "-") {
const flags = arg.slice(1).split("");
flags.forEach((flag) => {
args[flag] = true;
});
}
return args;
}, {});
var getApiKeys = () => {
const args = getArgs();
return {
evmKey: process.env.CRONOS_EVM_API_KEY || args.cronos_evm_api_key || "",
zkevmKey: process.env.CRONOS_ZKEVM_API_KEY || args.cronos_zkevm_api_key || ""
};
};
var determineNetwork = () => {
const args = getArgs();
const { evmKey, zkevmKey } = getApiKeys();
if (args.network) {
const network2 = args.network;
if (network2 in NETWORK_CONFIGS) {
return network2;
}
throw new Error(`Invalid network: ${network2}. Must be one of: ${Object.keys(NETWORK_CONFIGS).join(", ")}`);
}
if (evmKey && zkevmKey) {
console.error("\u{1F511} Both API keys detected, defaulting to Cronos Mainnet");
console.error("\u{1F4A1} Use --network=cronos-zkevm-mainnet to use zkEVM instead");
return "cronos-mainnet";
} else if (evmKey) {
console.error("\u{1F511} Cronos EVM API key detected, using Cronos Mainnet");
return "cronos-mainnet";
} else if (zkevmKey) {
console.error("\u{1F511} Cronos zkEVM API key detected, using zkEVM Mainnet");
return "cronos-zkevm-mainnet";
} else {
throw new Error("\u274C No API keys provided! Set CRONOS_EVM_API_KEY or CRONOS_ZKEVM_API_KEY");
}
};
var getApiKeyForNetwork = (network2) => {
const { evmKey, zkevmKey } = getApiKeys();
return network2 === "cronos-mainnet" ? evmKey : zkevmKey;
};
var network = determineNetwork();
var networkInfo = NETWORK_CONFIGS[network];
var apiKey = getApiKeyForNetwork(network);
if (apiKey) {
import_developer_platform_client.Client.init({
chain: networkInfo.chain,
apiKey
});
} else {
console.warn(`\u26A0\uFE0F No API key provided for ${network}. Some features may be limited.`);
}
function validateEnvironment() {
try {
const { evmKey, zkevmKey } = getApiKeys();
const keyType = network === "cronos-mainnet" ? "CRONOS_EVM_API_KEY" : "CRONOS_ZKEVM_API_KEY";
console.error(`\u2705 Cronos MCP environment configuration valid`);
console.error(`\u{1F4CD} Active Network: ${networkInfo.name}`);
console.error(`\u{1F4CD} RPC URL: ${networkInfo.rpcUrl}`);
console.error(`\u{1F4CD} Block Explorer: ${networkInfo.blockExplorer}`);
console.error(`\u{1F4CD} Native Currency: ${networkInfo.nativeCurrency}`);
if (apiKey) {
console.error(`\u{1F4CD} Active API Key (${keyType}): ****${apiKey.slice(-4)}`);
}
console.error(`\u{1F310} Network Availability:`);
console.error(` \u2022 Cronos Mainnet: ${evmKey ? "\u2705 Available" : "\u274C Missing CRONOS_EVM_API_KEY"}`);
console.error(` \u2022 zkEVM Mainnet: ${zkevmKey ? "\u2705 Available" : "\u274C Missing CRONOS_ZKEVM_API_KEY"}`);
} catch (error) {
console.error("\u274C Invalid environment configuration:", error);
throw error;
}
}
function initializeClientForNetwork(targetNetwork) {
const config = NETWORK_CONFIGS[targetNetwork];
const key = getApiKeyForNetwork(targetNetwork);
if (key) {
import_developer_platform_client.Client.init({
chain: config.chain,
apiKey: key
});
console.error(`\u{1F504} Switched to ${config.name} with API key ****${key.slice(-4)}`);
} else {
const requiredKey = targetNetwork === "cronos-mainnet" ? "CRONOS_EVM_API_KEY" : "CRONOS_ZKEVM_API_KEY";
throw new Error(`Missing ${requiredKey} for ${config.name}`);
}
}
function canSwitchToNetwork(targetNetwork) {
return !!getApiKeyForNetwork(targetNetwork);
}
function getAvailableNetworks() {
const { evmKey, zkevmKey } = getApiKeys();
const available = [];
if (evmKey) available.push("cronos-mainnet");
if (zkevmKey) available.push("cronos-zkevm-mainnet");
return available;
}
// src/index.ts
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
// src/agent/analytics.ts
var import_developer_platform_client2 = require("@crypto.com/developer-platform-client");
var CronosAnalyticsAgent = class {
network;
networkInfo;
constructor(targetNetwork) {
this.network = targetNetwork || "cronos-mainnet";
this.networkInfo = networkInfo;
if (targetNetwork && targetNetwork !== this.network) {
if (canSwitchToNetwork(targetNetwork)) {
initializeClientForNetwork(targetNetwork);
this.network = targetNetwork;
} else {
const requiredKey = targetNetwork === "cronos-mainnet" ? "CRONOS_EVM_API_KEY" : "CRONOS_ZKEVM_API_KEY";
console.warn(`\u26A0\uFE0F Cannot switch to ${targetNetwork}: Missing ${requiredKey}`);
console.warn(`\u{1F4CD} Continuing with default network: ${this.network}`);
}
}
console.error(`\u{1F50D} Cronos Analytics Agent initialized for ${this.network}`);
console.error(`\u{1F4CD} Network: ${this.networkInfo.name}`);
console.error(`\u{1F517} Block Explorer: ${this.networkInfo.blockExplorer}`);
}
// === BALANCE & TOKEN ANALYTICS ===
async getNativeTokenBalance(address) {
try {
const result = await import_developer_platform_client2.Token.getNativeTokenBalance(address);
return {
status: "success",
data: {
...result.data,
network: this.network,
currency: this.networkInfo.nativeCurrency
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get native balance",
network: this.network
};
}
}
async getERC20TokenBalance(address, contractAddress) {
try {
const result = await import_developer_platform_client2.Token.getERC20TokenBalance(address, contractAddress);
return {
status: "success",
data: {
...result.data,
network: this.network,
contractAddress
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get ERC20 balance",
network: this.network
};
}
}
async getWalletOverview(address) {
try {
const result = await import_developer_platform_client2.Wallet.balance(address);
return {
status: "success",
data: {
...result.data,
network: this.network,
address
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get wallet overview",
network: this.network
};
}
}
// === TRANSACTION ANALYTICS ===
async getTransactionByHash(transactionHash) {
try {
const result = await import_developer_platform_client2.Transaction.getTransactionByHash(transactionHash);
return {
status: "success",
data: {
...result.data,
network: this.network,
blockExplorer: `${this.networkInfo.blockExplorer}/tx/${transactionHash}`
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get transaction details",
network: this.network
};
}
}
async getTransactionStatus(transactionHash) {
try {
const result = await import_developer_platform_client2.Transaction.getTransactionStatus(transactionHash);
return {
status: "success",
data: {
...result.data,
network: this.network,
transactionHash
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get transaction status",
network: this.network
};
}
}
// === BLOCK ANALYTICS ===
async getCurrentBlock() {
try {
const result = await import_developer_platform_client2.Block.getCurrentBlock();
return {
status: "success",
data: {
...result.data,
network: this.network
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get current block",
network: this.network
};
}
}
async getBlockByTag(blockTag, includeTransactions = false) {
try {
const result = await import_developer_platform_client2.Block.getBlockByTag(blockTag, includeTransactions ? "true" : "false");
return {
status: "success",
data: {
...result.data,
network: this.network,
blockTag,
includeTransactions
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get block data",
network: this.network
};
}
}
// === DEFI ANALYTICS ===
async getWhitelistedTokens(protocol) {
try {
const result = await import_developer_platform_client2.Defi.getWhitelistedTokens(protocol);
return {
status: "success",
data: {
...result.data,
network: this.network,
protocol
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get whitelisted tokens",
network: this.network
};
}
}
async getAllFarms(protocol) {
try {
const result = await import_developer_platform_client2.Defi.getAllFarms(protocol);
return {
status: "success",
data: {
...result.data,
network: this.network,
protocol
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get farms",
network: this.network
};
}
}
async getFarmBySymbol(protocol, symbol) {
try {
const result = await import_developer_platform_client2.Defi.getFarmBySymbol(protocol, symbol);
return {
status: "success",
data: {
...result.data,
network: this.network,
protocol,
symbol
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get farm data",
network: this.network
};
}
}
// === CRONOS ID ANALYTICS ===
async resolveCronosId(cronosId) {
try {
const result = await import_developer_platform_client2.CronosId.forwardResolve(cronosId);
return {
status: "success",
data: {
...result.data,
network: this.network,
cronosId
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to resolve CronosId",
network: this.network
};
}
}
async reverseResolveCronosId(address) {
try {
const result = await import_developer_platform_client2.CronosId.reverseResolve(address);
return {
status: "success",
data: {
...result.data,
network: this.network,
address
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to reverse resolve address",
network: this.network
};
}
}
// === EXCHANGE & MARKET ANALYTICS ===
async getAllTickers() {
try {
const result = await import_developer_platform_client2.Exchange.getAllTickers();
return {
status: "success",
data: {
...result.data,
network: this.network,
exchangeInfo: "Crypto.com Exchange data"
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get exchange tickers",
network: this.network
};
}
}
async getTickerByInstrument(instrument) {
try {
const result = await import_developer_platform_client2.Exchange.getTickerByInstrument(instrument);
return {
status: "success",
data: {
...result.data,
network: this.network,
instrument
},
network: this.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get ticker data",
network: this.network
};
}
}
// === UTILITY METHODS ===
getNetworkInfo() {
return {
status: "success",
data: {
network: this.network,
name: this.networkInfo.name,
rpcUrl: this.networkInfo.rpcUrl,
blockExplorer: this.networkInfo.blockExplorer,
nativeCurrency: this.networkInfo.nativeCurrency,
hasApiKey: !!apiKey,
canSwitchNetworks: {
"cronos-mainnet": canSwitchToNetwork("cronos-mainnet"),
"cronos-zkevm-mainnet": canSwitchToNetwork("cronos-zkevm-mainnet")
}
},
network: this.network,
timestamp: Date.now()
};
}
// Format large numbers for better readability
formatBalance(balance, decimals = 18) {
const balanceNum = parseFloat(balance) / Math.pow(10, decimals);
if (balanceNum >= 1e9) return `${(balanceNum / 1e9).toFixed(2)}B`;
if (balanceNum >= 1e6) return `${(balanceNum / 1e6).toFixed(2)}M`;
if (balanceNum >= 1e3) return `${(balanceNum / 1e3).toFixed(2)}K`;
return balanceNum.toFixed(4);
}
// Validate Ethereum address format
isValidAddress(address) {
return /^0x[a-fA-F0-9]{40}$/.test(address);
}
// Validate transaction hash format
isValidTxHash(hash) {
return /^0x[a-fA-F0-9]{64}$/.test(hash);
}
// Validate CronosId format
isValidCronosId(name) {
return import_developer_platform_client2.CronosId.isCronosId(name);
}
};
// src/mcp/balance/get_balance_tools.ts
var import_zod = require("zod");
var GetNativeBalanceTool = {
name: "cronos_get_native_balance",
description: "Get native token balance (CRO/zkCRO) for any address on Cronos networks",
schema: {
address: import_zod.z.string().describe("Wallet address to check balance for (0x...)").regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid Ethereum address"),
network: import_zod.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getNativeTokenBalance(input.address);
return {
status: "success",
message: `\u2705 Native balance retrieved for ${input.address}`,
data: {
address: input.address,
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/address/${input.address}`
}
};
} catch (error) {
throw new Error(`Failed to get native balance: ${error.message}`);
}
}
};
var GetERC20BalanceTool = {
name: "cronos_get_erc20_balance",
description: "Get ERC20 token balance for any address and token contract on Cronos networks",
schema: {
address: import_zod.z.string().describe("Wallet address to check balance for (0x...)").regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid Ethereum address"),
contractAddress: import_zod.z.string().describe("ERC20 token contract address (0x...)").regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid contract address"),
network: import_zod.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getERC20TokenBalance(input.address, input.contractAddress);
return {
status: "success",
message: `\u2705 ERC20 balance retrieved for ${input.address}`,
data: {
address: input.address,
contractAddress: input.contractAddress,
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/token/${input.contractAddress}?a=${input.address}`
}
};
} catch (error) {
throw new Error(`Failed to get ERC20 balance: ${error.message}`);
}
}
};
var GetWalletOverviewTool = {
name: "cronos_get_wallet_overview",
description: "Get comprehensive wallet overview including all token balances and portfolio summary",
schema: {
address: import_zod.z.string().describe("Wallet address to analyze (0x...)").regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid Ethereum address"),
network: import_zod.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getWalletOverview(input.address);
return {
status: "success",
message: `\u2705 Wallet overview retrieved for ${input.address}`,
data: {
address: input.address,
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/address/${input.address}`,
analytics: {
totalTokens: result.data?.tokens?.length || 0,
hasActivity: result.data?.transactionCount > 0
}
}
};
} catch (error) {
throw new Error(`Failed to get wallet overview: ${error.message}`);
}
}
};
var GetNetworkInfoTool = {
name: "cronos_get_network_info",
description: "Get current network information and statistics",
schema: {
network: import_zod.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = targetAgent.getNetworkInfo();
return {
status: "success",
message: `\u2705 Network information retrieved`,
data: {
...result.data,
capabilities: [
"Native token balance queries",
"ERC20 token analytics",
"Transaction analysis",
"Contract information",
"Exchange data integration"
]
}
};
} catch (error) {
throw new Error(`Failed to get network info: ${error.message}`);
}
}
};
// src/mcp/transaction/get_transaction_tools.ts
var import_zod2 = require("zod");
var GetTransactionTool = {
name: "cronos_get_transaction",
description: "Get detailed transaction information by transaction hash",
schema: {
transactionHash: import_zod2.z.string().describe("Transaction hash to look up (0x...)").regex(/^0x[a-fA-F0-9]{64}$/, "Must be a valid transaction hash"),
network: import_zod2.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getTransactionByHash(input.transactionHash);
return {
status: "success",
message: `\u2705 Transaction details retrieved`,
data: {
transactionHash: input.transactionHash,
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/tx/${input.transactionHash}`
}
};
} catch (error) {
throw new Error(`Failed to get transaction: ${error.message}`);
}
}
};
var GetTransactionStatusTool = {
name: "cronos_get_transaction_status",
description: "Get transaction confirmation status and details",
schema: {
transactionHash: import_zod2.z.string().describe("Transaction hash to check status (0x...)").regex(/^0x[a-fA-F0-9]{64}$/, "Must be a valid transaction hash"),
network: import_zod2.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getTransactionStatus(input.transactionHash);
return {
status: "success",
message: `\u2705 Transaction status retrieved`,
data: {
transactionHash: input.transactionHash,
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/tx/${input.transactionHash}`,
statusSummary: {
isConfirmed: result.data?.status === "confirmed",
isPending: result.data?.status === "pending",
hasFailed: result.data?.status === "failed"
}
}
};
} catch (error) {
throw new Error(`Failed to get transaction status: ${error.message}`);
}
}
};
// src/mcp/block/get_block_tools.ts
var import_zod3 = require("zod");
var GetCurrentBlockTool = {
name: "cronos_get_current_block",
description: "Get the current latest block number and information",
schema: {
network: import_zod3.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getCurrentBlock();
return {
status: "success",
message: `\u2705 Current block information retrieved`,
data: {
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/block/${result.data?.blockNumber || "latest"}`
}
};
} catch (error) {
throw new Error(`Failed to get current block: ${error.message}`);
}
}
};
var GetBlockByTagTool = {
name: "cronos_get_block_by_tag",
description: "Get block information by block number, 'latest', or 'pending'",
schema: {
blockTag: import_zod3.z.string().describe("Block identifier ('latest', 'pending', or block number in hex like '0x1b4')"),
includeTransactions: import_zod3.z.boolean().optional().describe("Include full transaction details (default: false)"),
network: import_zod3.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getBlockByTag(input.blockTag, input.includeTransactions || false);
return {
status: "success",
message: `\u2705 Block data retrieved for ${input.blockTag}`,
data: {
...result.data,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/block/${input.blockTag}`
}
};
} catch (error) {
throw new Error(`Failed to get block data: ${error.message}`);
}
}
};
// src/mcp/defi/get_defi_tools.ts
var import_zod4 = require("zod");
var import_developer_platform_client3 = require("@crypto.com/developer-platform-client");
var GetAllFarmsTool = {
name: "cronos_get_all_farms",
description: "Get all yield farms for DeFi protocols with APR/APY data",
schema: {
protocol: import_zod4.z.enum(["h2finance", "vvsfinance"]).describe("DeFi protocol to query"),
network: import_zod4.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const protocol = input.protocol === "h2finance" ? import_developer_platform_client3.DefiProtocol.H2 : import_developer_platform_client3.DefiProtocol.VVS;
const result = await targetAgent.getAllFarms(protocol);
const farms = Array.isArray(result.data) ? result.data : [];
const activeFarms = farms.filter((farm) => !farm.isFinished);
return {
status: "success",
message: `\u2705 Farm data retrieved for ${input.protocol}`,
data: {
...result.data,
protocol: input.protocol,
summary: {
totalFarms: farms.length,
activeFarms: activeFarms.length,
finishedFarms: farms.length - activeFarms.length,
averageAPR: activeFarms.length > 0 ? activeFarms.reduce((sum, farm) => sum + (farm.baseApr || 0), 0) / activeFarms.length : 0
}
}
};
} catch (error) {
throw new Error(`Failed to get farms: ${error.message}`);
}
}
};
var GetFarmBySymbolTool = {
name: "cronos_get_farm_by_symbol",
description: "Get specific farm details by LP symbol",
schema: {
protocol: import_zod4.z.enum(["h2finance", "vvsfinance"]).describe("DeFi protocol to query"),
symbol: import_zod4.z.string().describe("LP symbol to query (e.g., 'zkCRO-MOON', 'CRO-USDC')"),
network: import_zod4.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const protocol = input.protocol === "h2finance" ? import_developer_platform_client3.DefiProtocol.H2 : import_developer_platform_client3.DefiProtocol.VVS;
const result = await targetAgent.getFarmBySymbol(protocol, input.symbol);
return {
status: "success",
message: `\u2705 Farm details retrieved for ${input.symbol}`,
data: {
...result.data,
protocol: input.protocol,
symbol: input.symbol,
yieldInfo: {
baseAPR: result.data?.baseApr || 0,
baseAPY: result.data?.baseApy || 0,
lpAPR: result.data?.lpApr || 0,
lpAPY: result.data?.lpApy || 0,
isActive: !result.data?.isFinished,
rewardEndDate: result.data?.rewardEndAt
}
}
};
} catch (error) {
throw new Error(`Failed to get farm data: ${error.message}`);
}
}
};
// src/mcp/cronosid/get_cronosid_tools.ts
var import_zod5 = require("zod");
var ResolveCronosIdTool = {
name: "cronos_resolve_cronosid",
description: "Resolve a CronosId (like alice.cro) to its wallet address",
schema: {
cronosId: import_zod5.z.string().describe("CronosId to resolve (e.g., 'alice.cro')").regex(/^[a-zA-Z0-9_-]+\.cro$/, "Must be a valid CronosId ending with .cro"),
network: import_zod5.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
if (!targetAgent.isValidCronosId(input.cronosId)) {
throw new Error("Invalid CronosId format. Must end with .cro");
}
const result = await targetAgent.resolveCronosId(input.cronosId);
return {
status: "success",
message: `\u2705 CronosId resolved: ${input.cronosId}`,
data: {
cronosId: input.cronosId,
...result.data,
blockExplorer: result.data?.address ? `${targetAgent.networkInfo.blockExplorer}/address/${result.data.address}` : void 0
}
};
} catch (error) {
throw new Error(`Failed to resolve CronosId: ${error.message}`);
}
}
};
var ReverseResolveCronosIdTool = {
name: "cronos_reverse_resolve_cronosid",
description: "Look up the CronosId associated with a wallet address",
schema: {
address: import_zod5.z.string().describe("Wallet address to reverse resolve (0x...)").regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid Ethereum address"),
network: import_zod5.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.reverseResolveCronosId(input.address);
return {
status: "success",
message: `\u2705 Address reverse resolved: ${input.address}`,
data: {
address: input.address,
...result.data,
hasCronosId: !!result.data?.name,
blockExplorer: `${targetAgent.networkInfo.blockExplorer}/address/${input.address}`
}
};
} catch (error) {
throw new Error(`Failed to reverse resolve address: ${error.message}`);
}
}
};
// src/mcp/vvs/get_vvs_tools.ts
var import_zod7 = require("zod");
// src/mcp/vvs/vvs_analytics.ts
var import_axios = __toESM(require("axios"));
var VVS_API_BASE = "https://api.vvs.finance/info/api";
var VVSAnalytics = class {
agent;
constructor(agent) {
this.agent = agent;
}
async getSupplyInfo() {
try {
const response = await import_axios.default.get(`${VVS_API_BASE}/supply`);
const data = response.data;
return {
status: "success",
data: {
...data,
network: this.agent.network,
formatted: {
totalSupply: this.formatTokenAmount(data.totalSupply),
circulatingSupply: this.formatTokenAmount(data.circulatingSupply),
burnedSupply: this.formatTokenAmount(data.burnedSupply),
burnRate: (parseFloat(data.burnedSupply) / parseFloat(data.totalSupply) * 100).toFixed(2) + "%"
}
},
network: this.agent.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get VVS supply info",
network: this.agent.network
};
}
}
async getSummary(limit) {
try {
const response = await import_axios.default.get(`${VVS_API_BASE}/summary`);
const data = response.data;
let pairs = Object.entries(data.data || {});
if (limit && pairs.length > limit) {
pairs = pairs.slice(0, limit);
}
const pairAnalysis = pairs.map(([pairId, pairData]) => ({
pairId,
...pairData,
tokens: pairId.split("_"),
liquidityUSD: parseFloat(pairData.liquidity || "0"),
liquidityCRO: parseFloat(pairData.liquidity_CRO || "0"),
volume24hUSD: parseFloat(pairData.base_volume || "0") + parseFloat(pairData.quote_volume || "0")
}));
const totalLiquidityUSD = pairAnalysis.reduce((sum, pair) => sum + pair.liquidityUSD, 0);
const totalVolume24h = pairAnalysis.reduce((sum, pair) => sum + pair.volume24hUSD, 0);
return {
status: "success",
data: {
updated_at: data.updated_at,
pairs: pairAnalysis,
network: this.agent.network,
summary: {
totalPairs: pairAnalysis.length,
totalLiquidityUSD,
totalVolume24hUSD: totalVolume24h,
averageLiquidityPerPair: totalLiquidityUSD / pairAnalysis.length,
topPairByLiquidity: pairAnalysis.sort((a, b) => b.liquidityUSD - a.liquidityUSD)[0]?.pairId
}
},
network: this.agent.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get VVS summary",
network: this.agent.network
};
}
}
async getTokens(limit) {
try {
const response = await import_axios.default.get(`${VVS_API_BASE}/tokens`);
const data = response.data;
let tokens = Object.entries(data.data || {});
if (limit && tokens.length > limit) {
tokens = tokens.slice(0, limit);
}
const tokenAnalysis = tokens.map(([address, tokenData]) => ({
address,
...tokenData,
priceUSD: parseFloat(tokenData.price || "0"),
priceCRO: parseFloat(tokenData.price_CRO || "0"),
isWCRO: address.toLowerCase() === "0x5c7f8a570d578ed84e63fdfa7b1ee72deae1ae23"
}));
const wcroToken = tokenAnalysis.find((token) => token.isWCRO);
return {
status: "success",
data: {
updated_at: data.updated_at,
tokens: tokenAnalysis,
network: this.agent.network,
summary: {
totalTokens: tokenAnalysis.length,
wcroPrice: wcroToken?.priceUSD || 0,
wcroAddress: "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
tokensWithUSDPrice: tokenAnalysis.filter((t) => t.priceUSD > 0).length,
tokensWithCROPrice: tokenAnalysis.filter((t) => t.priceCRO > 0).length
}
},
network: this.agent.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get VVS tokens",
network: this.agent.network
};
}
}
async getTokenInfo(tokenAddress) {
try {
const response = await import_axios.default.get(`${VVS_API_BASE}/tokens/${tokenAddress}`);
const data = response.data;
const isWCRO = tokenAddress.toLowerCase() === "0x5c7f8a570d578ed84e63fdfa7b1ee72deae1ae23";
return {
status: "success",
data: {
...data.data,
address: tokenAddress,
updated_at: data.updated_at,
network: this.agent.network,
priceUSD: parseFloat(data.data?.price || "0"),
priceCRO: parseFloat(data.data?.price_CRO || "0"),
isWCRO,
blockExplorer: `${this.agent.networkInfo.blockExplorer}/token/${tokenAddress}`
},
network: this.agent.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get token info",
network: this.agent.network
};
}
}
async getPairs(limit) {
try {
const response = await import_axios.default.get(`${VVS_API_BASE}/pairs`);
const data = response.data;
let pairs = Object.entries(data.data || {});
if (limit && pairs.length > limit) {
pairs = pairs.slice(0, limit);
}
const pairAnalysis = pairs.map(([pairId, pairData]) => ({
pairId,
...pairData,
tokens: pairId.split("_"),
liquidityUSD: parseFloat(pairData.liquidity || "0"),
liquidityCRO: parseFloat(pairData.liquidity_CRO || "0"),
baseVolume: parseFloat(pairData.base_volume || "0"),
quoteVolume: parseFloat(pairData.quote_volume || "0"),
price: parseFloat(pairData.price || "0"),
hasWCRO: pairId.includes("0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"),
isStablePair: this.isStablePair(pairData)
}));
const totalLiquidityUSD = pairAnalysis.reduce((sum, pair) => sum + pair.liquidityUSD, 0);
const wcroWallets = pairAnalysis.filter((pair) => pair.hasWCRO);
return {
status: "success",
data: {
updated_at: data.updated_at,
pairs: pairAnalysis,
network: this.agent.network,
summary: {
totalPairs: pairAnalysis.length,
totalLiquidityUSD,
wcroPairs: wcroWallets.length,
stablePairs: pairAnalysis.filter((p) => p.isStablePair).length,
topPairsByLiquidity: pairAnalysis.sort((a, b) => b.liquidityUSD - a.liquidityUSD).slice(0, 5).map((p) => ({ pairId: p.pairId, liquidity: p.liquidityUSD }))
}
},
network: this.agent.network,
timestamp: Date.now()
};
} catch (error) {
return {
status: "error",
message: error.message || "Failed to get VVS pairs",
network: this.agent.network
};
}
}
formatTokenAmount(amount) {
const num = parseFloat(amount) / 1e18;
if (num >= 1e12) return `${(num / 1e12).toFixed(2)}T`;
if (num >= 1e9) return `${(num / 1e9).toFixed(2)}B`;
if (num >= 1e6) return `${(num / 1e6).toFixed(2)}M`;
if (num >= 1e3) return `${(num / 1e3).toFixed(2)}K`;
return num.toFixed(2);
}
isStablePair(pairData) {
const stableTokens = ["USDT", "USDC", "DAI", "BUSD"];
const baseSymbol = pairData.base_symbol?.toUpperCase() || "";
const quoteSymbol = pairData.quote_symbol?.toUpperCase() || "";
return stableTokens.includes(baseSymbol) || stableTokens.includes(quoteSymbol);
}
};
// src/types.ts
var import_zod6 = require("zod");
var DefiProtocolSchema = import_zod6.z.enum(["h2finance", "vvsfinance"]);
var NetworkSchema = import_zod6.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]);
var AddressSchema = import_zod6.z.string().regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid Ethereum address");
var TxHashSchema = import_zod6.z.string().regex(/^0x[a-fA-F0-9]{64}$/, "Must be a valid transaction hash");
var CronosIdSchema = import_zod6.z.string().regex(/^[a-zA-Z0-9_-]+\.cro$/, "Must be a valid CronosId ending with .cro");
// src/mcp/vvs/get_vvs_tools.ts
var GetVVSSupplyTool = {
name: "cronos_get_vvs_supply",
description: "Get VVS token supply information (total, circulating, burned)",
schema: {
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getSupplyInfo();
return {
status: "success",
message: `\u2705 VVS supply information retrieved`,
data: {
...result.data,
protocol: "VVS Finance",
dex: "Leading DEX on Cronos"
}
};
} catch (error) {
throw new Error(`Failed to get VVS supply info: ${error.message}`);
}
}
};
var GetVVSSummaryTool = {
name: "cronos_get_vvs_summary",
description: "Get VVS DEX summary with top trading pairs and liquidity data",
schema: {
limit: import_zod7.z.number().optional().describe("Limit number of pairs returned (default: 50, max: 1000)").default(50),
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getSummary(input.limit || 50);
return {
status: "success",
message: `\u2705 VVS DEX summary retrieved`,
data: {
...result.data,
protocol: "VVS Finance",
description: "Top DEX on Cronos network",
wcroInfo: {
address: "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
note: "CRO is represented as WCRO in pairs"
}
}
};
} catch (error) {
throw new Error(`Failed to get VVS summary: ${error.message}`);
}
}
};
var GetVVSTokensTool = {
name: "cronos_get_vvs_tokens",
description: "Get all tokens available on VVS with price information",
schema: {
limit: import_zod7.z.number().optional().describe("Limit number of tokens returned (default: 100, max: 1000)").default(100),
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getTokens(input.limit || 100);
return {
status: "success",
message: `\u2705 VVS tokens retrieved`,
data: {
...result.data,
protocol: "VVS Finance",
wcroInfo: {
address: "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23",
note: "Canonical WCRO address used by VVS"
}
}
};
} catch (error) {
throw new Error(`Failed to get VVS tokens: ${error.message}`);
}
}
};
var GetVVSTokenInfoTool = {
name: "cronos_get_vvs_token_info",
description: "Get specific token information from VVS including USD and CRO prices",
schema: {
tokenAddress: AddressSchema.describe("Token contract address (0x...)"),
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getTokenInfo(input.tokenAddress);
return {
status: "success",
message: `\u2705 VVS token info retrieved for ${input.tokenAddress}`,
data: {
...result.data,
protocol: "VVS Finance",
tokenAddress: input.tokenAddress
}
};
} catch (error) {
throw new Error(`Failed to get VVS token info: ${error.message}`);
}
}
};
var GetVVSPairsTool = {
name: "cronos_get_vvs_pairs",
description: "Get all trading pairs on VVS with detailed liquidity and volume data",
schema: {
limit: import_zod7.z.number().optional().describe("Limit number of pairs returned (default: 100, max: 1000)").default(100),
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getPairs(input.limit || 100);
return {
status: "success",
message: `\u2705 VVS trading pairs retrieved`,
data: {
...result.data,
protocol: "VVS Finance",
dexInfo: {
type: "Automated Market Maker (AMM)",
chainName: targetAgent.networkInfo.name,
wcroAddress: "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
}
}
};
} catch (error) {
throw new Error(`Failed to get VVS pairs: ${error.message}`);
}
}
};
var GetVVSTopPairsTool = {
name: "cronos_get_vvs_top_pairs",
description: "Get top VVS trading pairs by liquidity with analytics",
schema: {
limit: import_zod7.z.number().optional().describe("Number of top pairs to return (default: 10, max: 50)").default(10),
sortBy: import_zod7.z.enum(["liquidity", "volume"]).optional().describe("Sort criteria (default: liquidity)"),
network: NetworkSchema.optional().describe("Network to query (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const vvsAnalytics = new VVSAnalytics(targetAgent);
const result = await vvsAnalytics.getPairs(1e3);
if (result.status !== "success" || !result.data?.pairs) {
throw new Error("Failed to fetch pairs data");
}
const sortBy = input.sortBy || "liquidity";
const limit = input.limit || 10;
const sortedPairs = result.data.pairs.sort((a, b) => {
if (sortBy === "volume") {
return b.baseVolume + b.quoteVolume - (a.baseVolume + a.quoteVolume);
}
return b.liquidityUSD - a.liquidityUSD;
}).slice(0, limit);
const analytics = {
totalLiquidityInTopPairs: sortedPairs.reduce((sum, pair) => sum + pair.liquidityUSD, 0),
totalVolumeInTopPairs: sortedPairs.reduce((sum, pair) => sum + pair.baseVolume + pair.quoteVolume, 0),
wcroWallets: sortedPairs.filter((pair) => pair.hasWCRO).length,
stablePairs: sortedPairs.filter((pair) => pair.isStablePair).length,
averageLiquidity: sortedPairs.reduce((sum, pair) => sum + pair.liquidityUSD, 0) / sortedPairs.length
};
return {
status: "success",
message: `\u2705 Top ${limit} VVS pairs retrieved (sorted by ${sortBy})`,
data: {
pairs: sortedPairs,
analytics,
sortBy,
limit,
protocol: "VVS Finance",
updated_at: result.data.updated_at,
network: targetAgent.network
}
};
} catch (error) {
throw new Error(`Failed to get top VVS pairs: ${error.message}`);
}
}
};
// src/mcp/market/get_market_tools.ts
var import_zod8 = require("zod");
var GetAllTickersTool = {
name: "cronos_get_all_tickers",
description: "Get all available trading pairs and market data from Crypto.com Exchange",
schema: {
limit: import_zod8.z.number().optional().describe("Limit number of results (default: 50, max: 200)").default(50),
network: import_zod8.z.enum(["cronos-mainnet", "cronos-zkevm-mainnet"]).optional().describe("Network context (defaults to configured network)")
},
handler: async (agent, input) => {
try {
const targetAgent = input.network && input.network !== agent.network ? new CronosAnalyticsAgent(input.network) : agent;
const result = await targetAgent.getAllTickers();
let tickers = result.data?.result || [];
if (input.limit && tickers.length > input.limit) {
tickers = tickers.slice(0, input.limit);
}
return {
status: "success",
message: `\u2705 Retrieved ${tickers.length} trading pairs`,
data: {
tickers,
count: tickers.length,
exchange: "Crypto.com Exchange",
network: targetAgent.network,
timestamp: Date.now(),
summary: {
totalPairs: result.data?.result?.length || 0,
croBasePairs: tickers.filter((t) => t.i && t.i.endsWith("_CRO")).length,
usdBasePairs: tickers.filter((t) => t.i && (t.i.endsWith("_USD") || t.i.endsWith("_USDT") || t.i.endsWith("_USDC"))).length
}
}
};
} catch (error) {
throw new Error(`Failed to get all tickers: ${error.message}`);
}
}
};
var GetTickerTool = {
name: "cronos_get_ticker",
description: "Get specific trading pair data and market information",
schema: {
instrument: import_zod8.z.string().describe("Trading pair instrument name (e.g., 'CRO_USD', 'BTC_CRO')").min(1),
network: import_zod8.z.enum(["cronos-mainnet", "cronos-zkevm-mainn