Skip to main content
Glama

contract_analyze

Analyze Hedera smart contracts to assess risks, examine activity patterns, evaluate gas usage, and classify contract functionality for security and performance insights.

Instructions

Deep analysis of a Hedera smart contract including activity patterns, caller distribution, gas usage, risk assessment, and functional classification. Costs 1 HBAR.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
api_keyYesYour HederaIntel API key
contract_idYesHedera contract ID to analyze (e.g. 0.0.123456)

Implementation Reference

  • The handler function for the `contract_analyze` tool, which fetches contract data, analyzes activities, gas usage, success rates, and performs a risk assessment.
    // --- contract_analyze ---
    if (name === "contract_analyze") {
      const payment = chargeForTool("contract_analyze", args.api_key);
      const base = getMirrorNodeBase();
    
      // Fetch contract info
      const contractRes = await axios.get(`${base}/api/v1/contracts/${args.contract_id}`);
      const contract = contractRes.data;
    
      // Fetch recent results (up to 100)
      const resultsRes = await axios.get(
        `${base}/api/v1/contracts/${args.contract_id}/results?limit=100&order=desc`
      ).catch(() => ({ data: { results: [] } }));
      const results = resultsRes.data.results || [];
    
      // Fetch contract logs
      const logsRes = await axios.get(
        `${base}/api/v1/contracts/${args.contract_id}/results/logs?limit=50&order=desc`
      ).catch(() => ({ data: { logs: [] } }));
      const logs = logsRes.data.logs || [];
    
      // Fetch state
      const stateRes = await axios.get(
        `${base}/api/v1/contracts/${args.contract_id}/state?limit=25`
      ).catch(() => ({ data: { state: [] } }));
      const stateEntries = stateRes.data.state || [];
    
      // Contract age
      const createdAt = contract.created_timestamp
        ? new Date(parseFloat(contract.created_timestamp) * 1000)
        : null;
      const ageDays = createdAt
        ? Math.floor((Date.now() - createdAt.getTime()) / (1000 * 60 * 60 * 24))
        : null;
    
      // Caller analysis
      const callerCounts = {};
      for (const r of results) {
        if (r.from) callerCounts[r.from] = (callerCounts[r.from] || 0) + 1;
      }
      const topCallers = Object.entries(callerCounts)
        .sort((a, b) => b[1] - a[1])
        .slice(0, 5)
        .map(([account, count]) => ({ account, call_count: count }));
    
      // Gas analysis
      const gasUsed = results.map(r => parseInt(r.gas_used || 0)).filter(g => g > 0);
      const avgGas = gasUsed.length > 0
        ? Math.round(gasUsed.reduce((a, b) => a + b, 0) / gasUsed.length)
        : 0;
      const maxGas = gasUsed.length > 0 ? Math.max(...gasUsed) : 0;
      const minGas = gasUsed.length > 0 ? Math.min(...gasUsed) : 0;
    
      // Success/failure rate
      // Mirror node contract results: status field is "0x1" (success) or "0x0" (fail)
      // result field may contain revert reason strings for failures
      const successCount = results.filter(r =>
        r.status === "0x1" || r.result === "SUCCESS" || (!r.status && !r.error_message)
      ).length;
      const failCount = results.filter(r =>
        r.status === "0x0" || (r.error_message && r.error_message.length > 0)
      ).length;
    
      // Activity trend - group by day
      const dayActivity = {};
      for (const r of results) {
        if (r.timestamp) {
          const day = new Date(parseFloat(r.timestamp) * 1000).toISOString().slice(0, 10);
          dayActivity[day] = (dayActivity[day] || 0) + 1;
        }
      }
      const activityByDay = Object.entries(dayActivity)
        .sort((a, b) => b[0].localeCompare(a[0]))
        .slice(0, 7)
        .map(([date, count]) => ({ date, calls: count }));
    
      // Function signature analysis from call data
      const functionCalls = {};
      for (const r of results) {
        if (r.function_parameters && r.function_parameters.length >= 10) {
          const sig = r.function_parameters.slice(0, 10);
          functionCalls[sig] = (functionCalls[sig] || 0) + 1;
        }
      }
      const topFunctions = Object.entries(functionCalls)
        .sort((a, b) => b[1] - a[1])
        .slice(0, 5)
        .map(([selector, count]) => ({ selector, call_count: count }));
    
      // Risk assessment
      const riskSignals = [];
      let riskScore = 0;
    
      if (!contract.admin_key) { riskSignals.push("No admin key - contract is immutable (good for decentralization)"); }
      if (contract.deleted) { riskScore += 50; riskSignals.push("Contract has been DELETED"); }
      if (failCount > 0 && failCount > successCount && results.length > 5) { riskScore += 20; riskSignals.push("High failure rate - more failed calls than successful ones"); }
      if (ageDays !== null && ageDays < 7) { riskScore += 15; riskSignals.push("Very new contract - deployed less than 7 days ago"); }
      if (topCallers.length === 1 && results.length > 10) { riskScore += 10; riskSignals.push("Single caller dominates all interactions"); }
      if (stateEntries.length === 0 && results.length > 0) { riskSignals.push("No readable state entries - contract may use non-standard storage"); }
      if (riskSignals.length === 0) riskSignals.push("No significant risk signals detected");
    
      const riskLevel = riskScore >= 40 ? "HIGH" : riskScore >= 15 ? "MEDIUM" : "LOW";
    
      // Contract classification guess
      let classification = "Unknown";
      const logTopics = logs.map(l => (l.topics || [])[0]).filter(Boolean);
      const uniqueTopics = [...new Set(logTopics)];
      if (uniqueTopics.some(t => t.startsWith("0xddf252ad"))) classification = "ERC20 / HTS Token";
      else if (uniqueTopics.some(t => t.startsWith("0xc3d58168"))) classification = "ERC1155 Multi-Token";
      else if (uniqueTopics.some(t => t.startsWith("0x17307eab"))) classification = "ERC721 NFT";
      else if (results.length > 50) classification = "High-activity contract (DEX, lending, or staking likely)";
      else if (results.length > 0) classification = "General purpose smart contract";
    
      return {
        contract_id: args.contract_id,
        evm_address: contract.evm_address || null,
        created_at: createdAt ? createdAt.toISOString() : null,
        age_days: ageDays,
        deleted: contract.deleted || false,
        hbar_balance: contract.balance?.balance
          ? (contract.balance.balance / 100000000).toFixed(4) + " HBAR"
          : "0.0000 HBAR",
        classification,
        activity: {
          total_calls_sampled: results.length,
          successful_calls: successCount,
          failed_calls: failCount,
          success_rate: results.length > 0 ? ((successCount / results.length) * 100).toFixed(1) + "%" : "unknown",
          unique_callers: Object.keys(callerCounts).length,
          recent_logs: logs.length,
          state_entries: stateEntries.length,
        },
        gas_analysis: {
          avg_gas_used: avgGas,
          max_gas_used: maxGas,
          min_gas_used: minGas,
        },
        top_callers: topCallers,
        top_function_selectors: topFunctions,
        activity_last_7_days: activityByDay,
        risk_assessment: {
          score: riskScore,
          level: riskLevel,
          signals: riskSignals,
        },
        payment,
        timestamp: new Date().toISOString(),
      };
    }
  • The definition and input schema for the `contract_analyze` tool.
    {
      name: "contract_analyze",
      description: "Deep analysis of a Hedera smart contract including activity patterns, caller distribution, gas usage, risk assessment, and functional classification. Costs 1.5 HBAR.",
      inputSchema: {
        type: "object",
        properties: {
          contract_id: { type: "string", description: "Hedera contract ID to analyze (e.g. 0.0.123456)" },
          api_key: { type: "string", description: "Your HederaIntel API key" },
        },
        required: ["contract_id", "api_key"],
      },
    },

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mountainmystic/hederatoolbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server