Skip to main content
Glama
ACaiSec
by ACaiSec

contract_info

Retrieve comprehensive on-chain EVM contract information by analyzing contract addresses, executing view functions, and providing detailed contract insights.

Instructions

获取 EVM 合约的完整链上信息,包括调用所有无参数的 view 函数

Args:
    contract_address: EVM 合约地址 (0x开头的42位十六进制字符串)

Returns:
    合约的详细信息,包括基础信息和所有view函数的调用结果

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contract_addressYes

Implementation Reference

  • The main handler function for the "contract_info" MCP tool, decorated with @mcp.tool() for registration. Includes input schema via type hints and docstring, validation, delegation to analyzer, and JSON output formatting.
    @mcp.tool()
    async def contract_info(contract_address: str):
        """
        获取 EVM 合约的完整链上信息,包括调用所有无参数的 view 函数
        
        Args:
            contract_address: EVM 合约地址 (0x开头的42位十六进制字符串)
        
        Returns:
            合约的详细信息,包括基础信息和所有view函数的调用结果
        """
        # 验证合约地址格式
        if not contract_address or not isinstance(contract_address, str):
            raise ValueError("合约地址不能为空且必须是字符串")
        
        if not contract_address.startswith("0x") or len(contract_address) != 42:
            raise ValueError("合约地址格式无效,必须是0x开头的42位十六进制字符串")
        
        try:
            print(f"🔍 开始分析合约: {contract_address}")
            
            # 执行合约分析
            result = await analyzer.analyze_contract(contract_address)
            
            # 格式化输出
            formatted_result = json.dumps(result, ensure_ascii=False, indent=2)
            
            print(f"✅ 合约分析完成: {contract_address}")
            
            return formatted_result
            
        except Exception as e:
            error_msg = f"合约分析失败: {str(e)}"
            print(f"❌ {error_msg}")
            
            error_response = {
                "status": "error",
                "error": error_msg,
                "contract_address": contract_address,
                "tool": "contract_info"
            }
            
            return json.dumps(error_response, ensure_ascii=False, indent=2)
  • Core helper method in ContractAnalyzer that performs the detailed contract analysis: initializes clients, validates address, fetches ABI, extracts and calls parameterless view functions, processes results, and returns structured data.
    async def analyze_contract(self, contract_address: str) -> Dict[str, Any]:
        """
        分析合约信息 - 主要业务逻辑
        
        Args:
            contract_address: 合约地址
            
        Returns:
            Dict: 分析结果
        """
        # 初始化检查
        if not await self.initialize():
            return {
                "status": "error",
                "error": "分析器初始化失败",
                "timestamp": datetime.now().isoformat()
            }
        
        # 步骤1: 验证地址格式
        if not is_valid_ethereum_address(contract_address):
            return {
                "status": "error",
                "error": f"无效的以太坊地址格式: {contract_address}",
                "timestamp": datetime.now().isoformat()
            }
        
        # 转换为校验和格式
        checksum_address = to_checksum_address(contract_address)
        
        # 步骤2: 检查是否为合约地址
        is_contract = await self.web3_client.is_contract_address(checksum_address)
        if not is_contract:
            return {
                "status": "error",
                "error": f"地址 {checksum_address} 不是合约地址",
                "timestamp": datetime.now().isoformat()
            }
        
        # 步骤3: 从 Etherscan 获取合约 ABI
        print(f"📡 正在获取合约 {checksum_address} 的 ABI...")
        abi = await self.etherscan_client.get_contract_abi(checksum_address)
        if not abi:
            return {
                "status": "error",
                "error": f"无法获取合约 ABI,可能合约未验证",
                "contract_address": checksum_address,
                "timestamp": datetime.now().isoformat()
            }
        
        # 步骤4: 筛选无参数的 view 函数
        view_functions = extract_view_functions(abi)
        if not view_functions:
            return {
                "status": "warning",
                "message": "合约中没有找到无参数的 view 函数",
                "contract_address": checksum_address,
                "total_functions": len([f for f in abi if f.get("type") == "function"]),
                "timestamp": datetime.now().isoformat()
            }
        
        print(f"🔍 找到 {len(view_functions)} 个无参数的 view 函数")
        
        # 步骤5: 创建合约实例
        contract = await self.web3_client.get_contract_instance(checksum_address, abi)
        if not contract:
            return {
                "status": "error",
                "error": "创建合约实例失败",
                "contract_address": checksum_address,
                "timestamp": datetime.now().isoformat()
            }
        
        # 步骤6: 批量调用 view 函数
        function_names = [func["name"] for func in view_functions]
        print(f"🚀 正在调用 {len(function_names)} 个函数...")
        
        call_results = await self.web3_client.batch_call_view_functions(
            contract, function_names
        )
        
        # 步骤7: 处理和格式化结果
        successful_calls = []
        failed_calls = []
        
        for i, result in enumerate(call_results):
            if result["status"] == "success":
                # 获取函数的输出类型信息
                func_info = view_functions[i]
                output_type = self._get_output_type(func_info)
                
                formatted_result = {
                    "function_name": result["function_name"],
                    "result": result["result"],
                    "type": output_type,
                    "status": "success"
                }
                
                # 格式化特殊类型的值
                if output_type.startswith("uint") and isinstance(result["result"], int):
                    if result["result"] > 10**15:  # 可能是 wei 值
                        formatted_result["formatted_value"] = self._format_large_number(result["result"])
                elif output_type == "address":
                    formatted_result["checksum_address"] = to_checksum_address(str(result["result"]))
                
                successful_calls.append(formatted_result)
            else:
                failed_calls.append({
                    "function_name": result["function_name"],
                    "error": result.get("error", "未知错误"),
                    "status": "failed"
                })
        
        # 获取额外的合约信息
        contract_name = await self.etherscan_client.get_contract_name(checksum_address)
        
        # 组装最终结果
        final_result = {
            "status": "success",
            "contract_address": checksum_address,
            "contract_name": contract_name,
            "analysis_summary": {
                "total_view_functions": len(view_functions),
                "successful_calls": len(successful_calls),
                "failed_calls": len(failed_calls)
            },
            "successful_functions": successful_calls,
            "failed_functions": failed_calls if failed_calls else None,
            "timestamp": datetime.now().isoformat()
        }
        
        print(f"✅ 分析完成: 成功调用 {len(successful_calls)} 个函数,失败 {len(failed_calls)} 个")
        
        return final_result

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

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/ACaiSec/ContractInfoMCP'

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