Spaces:
Sleeping
Sleeping
from typing import Dict, Any, Optional | |
from pydantic import BaseModel, PrivateAttr | |
from src.tools.base_tool import BaseWeb3Tool, Web3ToolInput | |
class DeFiLlamaTool(BaseWeb3Tool): | |
name: str = "defillama_data" | |
description: str = """Get DeFi protocol data, TVL, and yields from DeFiLlama. | |
Useful for: DeFi analysis, protocol rankings, TVL trends, yield farming data. | |
Input: protocol name or general DeFi query.""" | |
args_schema: type[BaseModel] = Web3ToolInput | |
_base_url: str = PrivateAttr(default="https://api.llama.fi") | |
def __init__(self): | |
super().__init__() | |
async def _arun(self, query: str, filters: Optional[Dict[str, Any]] = None) -> str: | |
try: | |
filters = filters or {} | |
if filters.get("type") == "tvl_overview": | |
return await self._get_tvl_overview() | |
elif filters.get("type") == "protocol_data": | |
return await self._get_protocol_data(query) | |
elif query: | |
return await self._search_protocols(query) | |
else: | |
return await self._get_top_protocols() | |
except Exception as e: | |
return f"DeFiLlama error: {str(e)}" | |
async def _get_top_protocols(self) -> str: | |
data = await self.make_request(f"{self.base_url}/protocols") | |
if not data: | |
return "No DeFi protocol data available" | |
top_protocols = sorted(data, key=lambda x: x.get("tvl", 0), reverse=True)[:10] | |
result = "π¦ **Top DeFi Protocols by TVL:**\n\n" | |
for i, protocol in enumerate(top_protocols, 1): | |
name = protocol.get("name", "Unknown") | |
tvl = protocol.get("tvl", 0) | |
change = protocol.get("change_1d", 0) | |
chain = protocol.get("chain", "Multi-chain") | |
emoji = "π" if change >= 0 else "π" | |
result += f"{i}. **{name}** ({chain}): ${tvl/1e9:.2f}B TVL {emoji} ({change:+.2f}%)\n" | |
return result | |
async def _get_tvl_overview(self) -> str: | |
try: | |
protocols_data = await self.make_request(f"{self.base_url}/protocols") | |
chains_data = await self.make_request(f"{self.base_url}/chains") | |
if not protocols_data or not chains_data: | |
return "TVL overview data unavailable" | |
total_tvl = sum(p.get("tvl", 0) for p in protocols_data) | |
top_chains = sorted(chains_data, key=lambda x: x.get("tvl", 0), reverse=True)[:5] | |
result = "π **DeFi TVL Overview:**\n\n" | |
result += f"π° **Total TVL**: ${total_tvl/1e9:.2f}B\n\n" | |
result += "**Top Chains by TVL:**\n" | |
for i, chain in enumerate(top_chains, 1): | |
name = chain.get("name", "Unknown") | |
tvl = chain.get("tvl", 0) | |
result += f"{i}. **{name}**: ${tvl/1e9:.2f}B\n" | |
return result | |
except Exception: | |
return await self._get_top_protocols() | |
async def _get_protocol_data(self, protocol: str) -> str: | |
protocols = await self.make_request(f"{self.base_url}/protocols") | |
if not protocols: | |
return f"No data available for {protocol}" | |
matching_protocol = None | |
for p in protocols: | |
if protocol.lower() in p.get("name", "").lower(): | |
matching_protocol = p | |
break | |
if not matching_protocol: | |
return f"Protocol '{protocol}' not found" | |
name = matching_protocol.get("name", "Unknown") | |
tvl = matching_protocol.get("tvl", 0) | |
change_1d = matching_protocol.get("change_1d", 0) | |
change_7d = matching_protocol.get("change_7d", 0) | |
chain = matching_protocol.get("chain", "Multi-chain") | |
category = matching_protocol.get("category", "Unknown") | |
result = f"ποΈ **{name} Protocol Analysis:**\n\n" | |
result += f"π° **TVL**: ${tvl/1e9:.2f}B\n" | |
result += f"π **24h Change**: {change_1d:+.2f}%\n" | |
result += f"π **7d Change**: {change_7d:+.2f}%\n" | |
result += f"βοΈ **Chain**: {chain}\n" | |
result += f"π·οΈ **Category**: {category}\n" | |
return result | |
async def _search_protocols(self, query: str) -> str: | |
protocols = await self.make_request(f"{self.base_url}/protocols") | |
if not protocols: | |
return "No protocol data available" | |
matching = [p for p in protocols if query.lower() in p.get("name", "").lower()][:5] | |
if not matching: | |
return f"No protocols found matching '{query}'" | |
result = f"π **Protocols matching '{query}':**\n\n" | |
for protocol in matching: | |
name = protocol.get("name", "Unknown") | |
tvl = protocol.get("tvl", 0) | |
chain = protocol.get("chain", "Multi-chain") | |
result += f"β’ **{name}** ({chain}): ${tvl/1e9:.2f}B TVL\n" | |
return result | |