File size: 5,257 Bytes
5f67151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python3
"""

Whale Tracking Router

GET /api/whales/transactions, GET /api/whales/activity

"""

from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import JSONResponse
from typing import Optional, List, Dict, Any
from datetime import datetime, timezone, timedelta
import logging

from backend.services.provider_fallback_manager import fallback_manager
from backend.services.data_resolver import get_data_resolver
from backend.services.persistence_service import PersistenceService
from database.db_manager import db_manager

logger = logging.getLogger(__name__)

router = APIRouter(
    prefix="/api/whales",
    tags=["Whale Tracking"]
)

persistence_service = PersistenceService()


def create_response(data: Any, source: str, attempted: List[str] = None) -> Dict[str, Any]:
    """Create standardized response"""
    return {
        "data": data,
        "meta": {
            "source": source,
            "generated_at": datetime.now(timezone.utc).isoformat(),
            "cache_ttl": 60,
            "attempted": attempted or [source]
        }
    }


@router.get("/transactions")
async def get_whale_transactions(

    limit: int = Query(50, description="Number of transactions"),

    chain: Optional[str] = Query(None, description="Blockchain (ethereum, bsc, tron)"),

    min_amount_usd: Optional[float] = Query(100000, description="Minimum amount in USD")

):
    """Get whale transactions"""
    attempted = []
    
    # Try database first
    try:
        transactions = await persistence_service.get_whale_transactions(
            limit=limit,
            chain=chain,
            min_amount=min_amount_usd
        )
        if transactions:
            attempted.append("database")
            return create_response(transactions, "database", attempted)
    except Exception as e:
        logger.warning(f"Database query failed: {e}")
        attempted.append("database")
    
    # Try HF Space
    try:
        resolver = await get_data_resolver()
        whale_data = await resolver.resolve_whale_transactions(limit=limit, chain=chain)
        if whale_data:
            attempted.append("hf")
            # Save to database
            await persistence_service.save_whale_transactions(whale_data)
            return create_response(whale_data, "hf", attempted)
    except Exception as e:
        logger.warning(f"HF Space unavailable: {e}")
        attempted.append("hf")
    
    # Fallback to external APIs
    try:
        result = await fallback_manager.fetch_with_fallback(
            endpoint="/whale/transactions",
            params={"limit": limit, "chain": chain or "ethereum"},
            transform_func=lambda x: x if isinstance(x, list) else []
        )
        attempted.extend(result.attempted)
        if result.success and result.data:
            # Filter by min_amount
            filtered = [
                tx for tx in result.data
                if tx.get("amount_usd", 0) >= min_amount_usd
            ]
            await persistence_service.save_whale_transactions(filtered)
            return create_response(filtered[:limit], result.source, attempted)
    except Exception as e:
        logger.error(f"External APIs failed: {e}")
        attempted.append("external_apis")
    
    # Return empty with attempted sources
    return create_response([], "none", attempted)


@router.get("/activity")
async def get_whale_activity(

    hours: int = Query(24, description="Hours to look back")

):
    """Get whale activity statistics"""
    attempted = []
    
    # Try database
    try:
        since = datetime.now(timezone.utc) - timedelta(hours=hours)
        activity = await persistence_service.get_whale_activity_stats(since)
        if activity:
            attempted.append("database")
            return create_response(activity, "database", attempted)
    except Exception as e:
        logger.warning(f"Database query failed: {e}")
        attempted.append("database")
    
    # Try HF Space
    try:
        resolver = await get_data_resolver()
        activity = await resolver.resolve_whale_activity(hours=hours)
        if activity:
            attempted.append("hf")
            return create_response(activity, "hf", attempted)
    except Exception as e:
        logger.warning(f"HF Space unavailable: {e}")
        attempted.append("hf")
    
    # Fallback to external
    try:
        result = await fallback_manager.fetch_with_fallback(
            endpoint="/whale/stats",
            params={"hours": hours},
            transform_func=lambda x: x if isinstance(x, dict) else {}
        )
        attempted.extend(result.attempted)
        if result.success:
            return create_response(result.data, result.source, attempted)
    except Exception as e:
        logger.error(f"External APIs failed: {e}")
        attempted.append("external_apis")
    
    # Return default stats
    default_stats = {
        "total_transactions": 0,
        "total_volume_usd": 0,
        "top_chains": [],
        "period_hours": hours
    }
    return create_response(default_stats, "default", attempted)