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
JavaScript
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