Skip to main content
Glama
utils.py4.96 kB
""" 工具函数模块 """ import re import json import asyncio from typing import Any, Dict, List, Optional from web3 import Web3 def is_valid_ethereum_address(address: str) -> bool: """ 验证以太坊地址格式是否有效 Args: address: 以太坊地址字符串 Returns: bool: 地址是否有效 """ if not address: return False # 检查是否以 0x 开头且长度为 42 if not re.match(r'^0x[a-fA-F0-9]{40}$', address): return False return True def is_checksum_address(address: str) -> bool: """ 验证地址是否为有效的校验和地址 Args: address: 以太坊地址字符串 Returns: bool: 是否为有效的校验和地址 """ try: return Web3.is_checksum_address(address) except Exception: return False def to_checksum_address(address: str) -> str: """ 将地址转换为校验和格式 Args: address: 以太坊地址字符串 Returns: str: 校验和格式的地址 """ try: return Web3.to_checksum_address(address) except Exception: return address def format_wei_value(value: int, decimals: int = 18) -> str: """ 格式化 Wei 值为可读的小数格式 Args: value: Wei 值 decimals: 小数位数,默认18 Returns: str: 格式化后的数值字符串 """ try: if value == 0: return "0" divisor = 10 ** decimals result = value / divisor # 移除尾随零 formatted = f"{result:.{decimals}f}".rstrip('0').rstrip('.') return formatted if formatted else "0" except Exception: return str(value) def safe_json_loads(data: str) -> Optional[Any]: """ 安全的 JSON 解析 Args: data: JSON 字符串 Returns: 解析后的数据或 None """ try: return json.loads(data) except (json.JSONDecodeError, TypeError): return None def extract_view_functions(abi: List[Dict]) -> List[Dict]: """ 从 ABI 中提取无参数的 view 函数 Args: abi: 合约 ABI 列表 Returns: List[Dict]: 符合条件的函数列表 """ view_functions = [] for item in abi: if ( item.get("type") == "function" and item.get("stateMutability") in ["view", "pure"] and len(item.get("inputs", [])) == 0 ): view_functions.append(item) return view_functions def format_function_result(func_name: str, result: Any, output_type: str) -> Dict[str, Any]: """ 格式化函数调用结果 Args: func_name: 函数名称 result: 函数返回值 output_type: 返回值类型 Returns: Dict: 格式化后的结果 """ formatted_result = { "function_name": func_name, "result": result, "type": output_type, "status": "success" } # 对特定类型进行格式化 if output_type.startswith("uint") and isinstance(result, int): formatted_result["formatted_value"] = format_wei_value(result) if "256" in output_type else str(result) elif output_type == "address" and isinstance(result, str): formatted_result["checksum_address"] = to_checksum_address(result) elif output_type == "bool": formatted_result["result"] = bool(result) return formatted_result async def retry_with_backoff( func, max_retries: int = 3, base_delay: float = 1.0, backoff_factor: float = 2.0, *args, **kwargs ) -> Any: """ 带指数退避的重试机制 Args: func: 要重试的函数 max_retries: 最大重试次数 base_delay: 基础延迟时间(秒) backoff_factor: 退避因子 *args, **kwargs: 传递给函数的参数 Returns: 函数执行结果 """ last_exception = None for attempt in range(max_retries + 1): try: if asyncio.iscoroutinefunction(func): return await func(*args, **kwargs) else: return func(*args, **kwargs) except Exception as e: last_exception = e if attempt == max_retries: break delay = base_delay * (backoff_factor ** attempt) await asyncio.sleep(delay) raise last_exception def truncate_string(text: str, max_length: int = 100) -> str: """ 截断字符串到指定长度 Args: text: 原始字符串 max_length: 最大长度 Returns: str: 截断后的字符串 """ if len(text) <= max_length: return text return text[:max_length - 3] + "..."

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