UNPKG

devion-mcp-server

Version:

MCP server for Devion blockchain infrastructure - AI-native blockchain data access for developers and AI agents

311 lines 12.5 kB
import { DevionSDK } from 'devion-sdk'; import { z } from 'zod'; import { SUPPORTED_NETWORKS } from '../types.js'; export const getMultiChainBalances = { name: 'get_multichain_balances', description: 'Get native token balances for an address across multiple blockchain networks simultaneously', inputSchema: { type: 'object', properties: { address: { type: 'string', description: 'Ethereum address to check balance for (0x...)', pattern: '^0x[a-fA-F0-9]{40}$' }, networks: { type: 'array', items: { type: 'string', enum: SUPPORTED_NETWORKS }, description: 'Array of networks to check (defaults to all mainnet networks)', minItems: 2, maxItems: 6 }, include_usd_values: { type: 'boolean', description: 'Include estimated USD values for each balance', default: false }, min_balance_threshold: { type: 'number', description: 'Only show networks with balance above this threshold (in native tokens)', minimum: 0, default: 0 } }, required: ['address'] }, async handler(args) { const schema = z.object({ address: z.string().regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address'), networks: z.array(z.enum(SUPPORTED_NETWORKS)).default([ 'ethereum-mainnet', 'base-mainnet', 'arbitrum-mainnet', 'polygon-mainnet' ]), include_usd_values: z.boolean().default(false), min_balance_threshold: z.number().min(0).default(0) }); const { address, networks, include_usd_values, min_balance_threshold } = schema.parse(args); const errors = []; let totalUsdValue = 0; const balancePromises = networks.map(async (network) => { try { const sdk = new DevionSDK({ apiKey: process.env.DEVION_API_KEY, baseURL: 'https://api.devion.dev', network: network }); const [balance, blockNumber] = await Promise.all([ sdk.getBalance(address, { formatted: true }), sdk.getBlockNumber() ]); const balanceFloat = parseFloat(balance); const currency = getNetworkCurrency(network); const estimatedUsdValue = include_usd_values ? balanceFloat * getEstimatedPrice(network) : undefined; if (estimatedUsdValue) { totalUsdValue += estimatedUsdValue; } if (balanceFloat >= min_balance_threshold) { const multiChainBalance = { network, balance, balance_formatted: `${balance} ${currency}`, currency, block_number: typeof blockNumber === 'string' ? parseInt(blockNumber, 16) : blockNumber, estimated_usd_value: estimatedUsdValue }; return multiChainBalance; } return null; } catch (error) { errors.push({ network, error: error instanceof Error ? error.message : 'Unknown error' }); return null; } }); const results = await Promise.all(balancePromises); const validBalances = results.filter((b) => b !== null); const response = { success: validBalances.length > 0, data: { address, balances: validBalances, summary: { networks_checked: networks.length, networks_with_balance: validBalances.length, networks_failed: errors.length, total_estimated_usd_value: include_usd_values ? Math.round(totalUsdValue * 100) / 100 : undefined, threshold_applied: min_balance_threshold > 0 ? min_balance_threshold : undefined }, timestamp: new Date().toISOString() } }; if (include_usd_values && validBalances.length > 0) { response.data.portfolio_breakdown = validBalances .filter(b => b.estimated_usd_value && b.estimated_usd_value > 0) .map(b => ({ network: b.network, percentage: totalUsdValue > 0 ? Math.round((b.estimated_usd_value / totalUsdValue) * 100 * 100) / 100 : 0, usd_value: b.estimated_usd_value })) .sort((a, b) => b.usd_value - a.usd_value); } if (errors.length > 0) { response.data.errors = errors; } return response; } }; export const compareGasCosts = { name: 'compare_gas_costs', description: 'Compare current gas prices and transaction costs across multiple blockchain networks to find the most cost-effective option', inputSchema: { type: 'object', properties: { networks: { type: 'array', items: { type: 'string', enum: SUPPORTED_NETWORKS }, description: 'Networks to compare (defaults to all mainnet networks)', minItems: 2, maxItems: 6 }, transaction_type: { type: 'string', enum: ['simple_transfer', 'erc20_transfer', 'contract_interaction', 'dex_swap'], description: 'Type of transaction to estimate costs for', default: 'simple_transfer' }, include_time_estimates: { type: 'boolean', description: 'Include estimated confirmation time for each network', default: true } }, required: [] }, async handler(args) { const schema = z.object({ networks: z.array(z.enum(SUPPORTED_NETWORKS)).default([ 'ethereum-mainnet', 'base-mainnet', 'arbitrum-mainnet', 'polygon-mainnet' ]), transaction_type: z.enum(['simple_transfer', 'erc20_transfer', 'contract_interaction', 'dex_swap']).default('simple_transfer'), include_time_estimates: z.boolean().default(true) }); const { networks, transaction_type, include_time_estimates } = schema.parse(args); const comparisons = []; const errors = []; for (const network of networks) { try { const sdk = new DevionSDK({ apiKey: process.env.DEVION_API_KEY, baseURL: 'https://api.devion.dev', network: network }); const gasPrice = await sdk.rpc('eth_gasPrice'); const gasPriceWei = parseInt(gasPrice, 16); const gasPriceGwei = gasPriceWei / 1e9; const gasLimit = getGasLimit(transaction_type); const costEth = (gasPriceGwei * gasLimit) / 1e9; const ethPrice = getEstimatedPrice(network); const costUsd = costEth * ethPrice; const comparison = { network, gas_price_gwei: Math.round(gasPriceGwei * 100) / 100, estimated_cost_usd: Math.round(costUsd * 100) / 100, estimated_time_seconds: include_time_estimates ? getEstimatedConfirmationTime(network) : 0, relative_cost: 'moderate' }; comparisons.push(comparison); } catch (error) { errors.push({ network, error: error instanceof Error ? error.message : 'Unknown error' }); } } comparisons.sort((a, b) => a.estimated_cost_usd - b.estimated_cost_usd); comparisons.forEach((comp, index) => { if (index === 0) comp.relative_cost = 'cheapest'; else if (index === comparisons.length - 1) comp.relative_cost = 'expensive'; else comp.relative_cost = 'moderate'; }); const response = { success: comparisons.length > 0, data: { transaction_type, gas_limit_estimate: getGasLimit(transaction_type), networks_compared: comparisons, summary: { cheapest_network: comparisons[0]?.network, cheapest_cost_usd: comparisons[0]?.estimated_cost_usd, most_expensive_network: comparisons[comparisons.length - 1]?.network, most_expensive_cost_usd: comparisons[comparisons.length - 1]?.estimated_cost_usd, cost_difference_usd: comparisons.length > 1 ? Math.round((comparisons[comparisons.length - 1].estimated_cost_usd - comparisons[0].estimated_cost_usd) * 100) / 100 : 0, networks_analyzed: comparisons.length, networks_failed: errors.length }, recommendations: generateRecommendations(comparisons, transaction_type), timestamp: new Date().toISOString() } }; if (errors.length > 0) { response.data.errors = errors; } return response; } }; function getNetworkCurrency(network) { switch (network) { case 'ethereum-mainnet': return 'ETH'; case 'polygon-mainnet': return 'MATIC'; case 'base-mainnet': case 'base-sepolia': return 'ETH'; case 'arbitrum-mainnet': case 'arbitrum-sepolia': return 'ETH'; default: return 'ETH'; } } function getEstimatedPrice(network) { switch (network) { case 'ethereum-mainnet': case 'base-mainnet': case 'arbitrum-mainnet': return 2500; case 'polygon-mainnet': return 0.8; default: return 0; } } function getGasLimit(transactionType) { switch (transactionType) { case 'simple_transfer': return 21000; case 'erc20_transfer': return 65000; case 'contract_interaction': return 100000; case 'dex_swap': return 200000; default: return 21000; } } function getEstimatedConfirmationTime(network) { switch (network) { case 'ethereum-mainnet': return 12; case 'polygon-mainnet': return 2; case 'base-mainnet': return 2; case 'arbitrum-mainnet': return 1; default: return 12; } } function generateRecommendations(comparisons, transactionType) { if (comparisons.length === 0) return []; const recommendations = []; const cheapest = comparisons[0]; const mostExpensive = comparisons[comparisons.length - 1]; if (cheapest) { recommendations.push(`For ${transactionType}, ${cheapest.network} is the most cost-effective at $${cheapest.estimated_cost_usd}`); } if (comparisons.length > 1 && mostExpensive && cheapest) { recommendations.push(`${mostExpensive.network} is ${Math.round((mostExpensive.estimated_cost_usd / cheapest.estimated_cost_usd) * 100) / 100}x more expensive`); } const layer2Networks = comparisons.filter(c => c.network.includes('base') || c.network.includes('arbitrum') || c.network.includes('polygon')); if (layer2Networks.length > 0) { recommendations.push('Consider Layer 2 networks for significantly lower costs'); } if (transactionType === 'simple_transfer' && cheapest && cheapest.estimated_cost_usd > 5) { recommendations.push('High gas costs detected - consider waiting for lower network congestion'); } return recommendations; } //# sourceMappingURL=multichain.js.map