devion-mcp-server
Version:
MCP server for Devion blockchain infrastructure - AI-native blockchain data access for developers and AI agents
207 lines • 8.07 kB
JavaScript
import { DevionSDK } from 'devion-sdk';
import { z } from 'zod';
import { SUPPORTED_NETWORKS } from '../types.js';
export const getLatestBlock = {
name: 'get_latest_block',
description: 'Get the latest block information including number, hash, timestamp, and gas data',
inputSchema: {
type: 'object',
properties: {
network: {
type: 'string',
enum: SUPPORTED_NETWORKS,
description: 'Blockchain network to query (defaults to ethereum-mainnet)'
},
include_transactions: {
type: 'boolean',
description: 'Include transaction hashes in the block data',
default: false
}
},
required: []
},
async handler(args) {
const schema = z.object({
network: z.enum(SUPPORTED_NETWORKS).default('ethereum-mainnet'),
include_transactions: z.boolean().default(false)
});
const { network, include_transactions } = schema.parse(args);
const sdk = new DevionSDK({
apiKey: process.env.DEVION_API_KEY,
baseURL: 'https://api.devion.dev',
network: network
});
try {
const block = await sdk.rpc('eth_getBlockByNumber', ['latest', include_transactions]);
if (!block) {
return {
success: false,
error: 'Failed to fetch latest block',
details: { network }
};
}
const blockData = {
number: parseInt(block.number, 16),
hash: block.hash,
parent_hash: block.parentHash,
timestamp: parseInt(block.timestamp, 16),
timestamp_formatted: new Date(parseInt(block.timestamp, 16) * 1000).toISOString(),
gas_limit: parseInt(block.gasLimit, 16),
gas_used: parseInt(block.gasUsed, 16),
gas_utilization: Math.round((parseInt(block.gasUsed, 16) / parseInt(block.gasLimit, 16)) * 100 * 100) / 100,
transaction_count: Array.isArray(block.transactions) ? block.transactions.length : 0,
miner: block.miner,
difficulty: block.difficulty,
total_difficulty: block.totalDifficulty
};
const result = {
success: true,
data: {
block: blockData,
network,
timestamp: new Date().toISOString()
}
};
if (include_transactions && Array.isArray(block.transactions)) {
result.data.transactions = block.transactions.slice(0, 10);
result.data.total_transactions = block.transactions.length;
if (block.transactions.length > 10) {
result.data.note = 'Only first 10 transactions shown for performance. Use get_transaction_details for specific transactions.';
}
}
return result;
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error occurred',
details: {
network,
timestamp: new Date().toISOString()
}
};
}
}
};
export const getGasPrices = {
name: 'get_gas_prices',
description: 'Get current gas prices for one or multiple networks to help optimize transaction costs',
inputSchema: {
type: 'object',
properties: {
networks: {
type: 'array',
items: {
type: 'string',
enum: SUPPORTED_NETWORKS
},
description: 'Array of networks to get gas prices for (defaults to all mainnet networks)',
minItems: 1,
maxItems: 6
},
include_estimates: {
type: 'boolean',
description: 'Include transaction cost estimates for common operations',
default: false
}
},
required: []
},
async handler(args) {
const schema = z.object({
networks: z.array(z.enum(SUPPORTED_NETWORKS)).default([
'ethereum-mainnet',
'base-mainnet',
'arbitrum-mainnet',
'polygon-mainnet'
]),
include_estimates: z.boolean().default(false)
});
const { networks, include_estimates } = schema.parse(args);
const results = [];
const errors = [];
for (const network of networks) {
try {
const apiKey = process.env.DEVION_API_KEY;
if (!apiKey) {
errors.push({
network: network,
error: 'DEVION_API_KEY environment variable not set'
});
continue;
}
const sdk = new DevionSDK({
apiKey: apiKey,
baseURL: 'https://api.devion.dev',
network: network
});
const [gasPrice, blockNumber] = await Promise.all([
sdk.rpc('eth_gasPrice'),
sdk.getBlockNumber()
]);
const gasPriceWei = parseInt(gasPrice, 16);
const gasPriceGwei = gasPriceWei / 1e9;
const gasPriceData = {
network,
gas_price_wei: gasPriceWei,
gas_price_gwei: Math.round(gasPriceGwei * 100) / 100,
gas_price_formatted: `${Math.round(gasPriceGwei * 100) / 100} gwei`,
block_number: typeof blockNumber === 'string' ? parseInt(blockNumber, 16) : blockNumber,
timestamp: new Date().toISOString()
};
results.push(gasPriceData);
}
catch (error) {
errors.push({
network,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
}
const response = {
success: results.length > 0,
data: {
gas_prices: results,
networks_queried: networks.length,
successful_queries: results.length,
failed_queries: errors.length,
timestamp: new Date().toISOString()
}
};
if (include_estimates && results.length > 0) {
response.data.estimates = {
simple_transfer: results.map(gp => ({
network: gp.network,
gas_limit: 21000,
cost_gwei: Math.round(gp.gas_price_gwei * 21000 * 100) / 100,
cost_eth: (gp.gas_price_gwei * 21000) / 1e9,
cost_usd_estimate: ((gp.gas_price_gwei * 21000) / 1e9) * getEstimatedEthPrice(gp.network)
})),
erc20_transfer: results.map(gp => ({
network: gp.network,
gas_limit: 65000,
cost_gwei: Math.round(gp.gas_price_gwei * 65000 * 100) / 100,
cost_eth: (gp.gas_price_gwei * 65000) / 1e9,
cost_usd_estimate: ((gp.gas_price_gwei * 65000) / 1e9) * getEstimatedEthPrice(gp.network)
}))
};
}
if (errors.length > 0) {
response.data.errors = errors;
}
return response;
}
};
function getEstimatedEthPrice(network) {
switch (network) {
case 'ethereum-mainnet':
case 'base-mainnet':
case 'arbitrum-mainnet':
return 2500;
case 'polygon-mainnet':
return 0.8;
default:
return 0;
}
}
//# sourceMappingURL=blocks.js.map