Spaces:
Sleeping
Sleeping
from typing import Dict, Any, Optional | |
from pydantic import BaseModel, PrivateAttr | |
from src.tools.base_tool import BaseWeb3Tool, Web3ToolInput | |
from src.utils.config import config | |
class EtherscanTool(BaseWeb3Tool): | |
name: str = "etherscan_data" | |
description: str = """Get Ethereum blockchain data from Etherscan. | |
Useful for: transaction analysis, address information, gas prices, token data. | |
Input: Ethereum address, transaction hash, or general blockchain query.""" | |
args_schema: type[BaseModel] = Web3ToolInput | |
_base_url: str = PrivateAttr(default="https://api.etherscan.io/api") | |
_api_key: Optional[str] = PrivateAttr(default=None) | |
def __init__(self): | |
super().__init__() | |
self._api_key = config.ETHERSCAN_API_KEY | |
async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str: | |
if not self.api_key: | |
return "β Etherscan API key not configured" | |
try: | |
filters = filters or {} | |
if filters.get("type") == "gas_prices": | |
return await self._get_gas_prices() | |
elif filters.get("type") == "eth_stats": | |
return await self._get_eth_stats() | |
elif self._is_address(query): | |
return await self._get_address_info(query) | |
elif self._is_tx_hash(query): | |
return await self._get_transaction_info(query) | |
else: | |
return await self._get_gas_prices() | |
except Exception as e: | |
return f"Etherscan error: {str(e)}" | |
def _is_address(self, query: str) -> bool: | |
return len(query) == 42 and query.startswith("0x") | |
def _is_tx_hash(self, query: str) -> bool: | |
return len(query) == 66 and query.startswith("0x") | |
async def _get_gas_prices(self) -> str: | |
params = { | |
"module": "gastracker", | |
"action": "gasoracle", | |
"apikey": self.api_key | |
} | |
data = await self.make_request(self.base_url, params) | |
if data.get("status") != "1": | |
return "Gas price data unavailable" | |
result_data = data.get("result", {}) | |
safe_gas = result_data.get("SafeGasPrice", "N/A") | |
standard_gas = result_data.get("StandardGasPrice", "N/A") | |
fast_gas = result_data.get("FastGasPrice", "N/A") | |
result = "β½ **Ethereum Gas Prices:**\n\n" | |
result += f"π **Safe**: {safe_gas} gwei\n" | |
result += f"β‘ **Standard**: {standard_gas} gwei\n" | |
result += f"π **Fast**: {fast_gas} gwei\n" | |
return result | |
async def _get_eth_stats(self) -> str: | |
params = { | |
"module": "stats", | |
"action": "ethsupply", | |
"apikey": self.api_key | |
} | |
data = await self.make_request(self.base_url, params) | |
if data.get("status") != "1": | |
return "Ethereum stats unavailable" | |
eth_supply = int(data.get("result", 0)) / 1e18 | |
result = "π **Ethereum Network Stats:**\n\n" | |
result += f"π **ETH Supply**: {eth_supply:,.0f} ETH\n" | |
return result | |
async def _get_address_info(self, address: str) -> str: | |
params = { | |
"module": "account", | |
"action": "balance", | |
"address": address, | |
"tag": "latest", | |
"apikey": self.api_key | |
} | |
data = await self.make_request(self.base_url, params) | |
if data.get("status") != "1": | |
return f"Address information unavailable for {address}" | |
balance_wei = int(data.get("result", 0)) | |
balance_eth = balance_wei / 1e18 | |
result = f"π **Address Information:**\n\n" | |
result += f"**Address**: {address}\n" | |
result += f"π° **Balance**: {balance_eth:.4f} ETH\n" | |
return result | |
async def _get_transaction_info(self, tx_hash: str) -> str: | |
params = { | |
"module": "proxy", | |
"action": "eth_getTransactionByHash", | |
"txhash": tx_hash, | |
"apikey": self.api_key | |
} | |
data = await self.make_request(self.base_url, params) | |
if not data.get("result"): | |
return f"Transaction not found: {tx_hash}" | |
tx = data.get("result", {}) | |
value_wei = int(tx.get("value", "0x0"), 16) | |
value_eth = value_wei / 1e18 | |
gas_price = int(tx.get("gasPrice", "0x0"), 16) / 1e9 | |
result = f"π **Transaction Information:**\n\n" | |
result += f"**Hash**: {tx_hash}\n" | |
result += f"**From**: {tx.get('from', 'N/A')}\n" | |
result += f"**To**: {tx.get('to', 'N/A')}\n" | |
result += f"π° **Value**: {value_eth:.4f} ETH\n" | |
result += f"β½ **Gas Price**: {gas_price:.2f} gwei\n" | |
return result | |