Automated Action 5bb78bd9be Implement Solana arbitrage analytics backend
- Create project structure with FastAPI
- Add database models for blocks, transactions, arbitrages, pools, and DEXes
- Implement Solana RPC client for fetching blockchain data
- Create arbitrage detection algorithm
- Implement comprehensive API endpoints for analytics
- Set up database migrations with Alembic
- Add detailed project documentation

generated with BackendIM... (backend.im)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-05-12 14:13:06 +00:00

99 lines
3.5 KiB
Python

from typing import List, Optional, Dict, Any, Union, Tuple
from sqlalchemy import func, desc, or_, and_
from sqlalchemy.orm import Session, joinedload
from app.crud.base import CRUDBase
from app.models.pool import Pool
from app.models.dex import Dex
from app.schemas.pool import PoolCreate, PoolUpdate
class CRUDPool(CRUDBase[Pool, PoolCreate, PoolUpdate]):
"""CRUD operations for liquidity pools."""
def get_by_address(self, db: Session, *, address: str) -> Optional[Pool]:
"""Get a pool by its address."""
return db.query(Pool).filter(Pool.address == address).first()
def get_by_dex(
self, db: Session, *, dex_id: int, skip: int = 0, limit: int = 100
) -> List[Pool]:
"""Get pools for a specific DEX."""
return db.query(Pool).filter(
Pool.dex_id == dex_id
).offset(skip).limit(limit).all()
def get_by_token(
self, db: Session, *, token_address: str, skip: int = 0, limit: int = 100
) -> List[Pool]:
"""Get pools that contain a specific token."""
return db.query(Pool).filter(
or_(
Pool.token_a_address == token_address,
Pool.token_b_address == token_address
)
).offset(skip).limit(limit).all()
def get_by_token_pair(
self, db: Session, *, token_a: str, token_b: str, skip: int = 0, limit: int = 100
) -> List[Pool]:
"""Get pools for a specific token pair."""
return db.query(Pool).filter(
or_(
and_(Pool.token_a_address == token_a, Pool.token_b_address == token_b),
and_(Pool.token_a_address == token_b, Pool.token_b_address == token_a)
)
).offset(skip).limit(limit).all()
def get_by_tvl_range(
self, db: Session, *, min_tvl: float, max_tvl: Optional[float] = None,
skip: int = 0, limit: int = 100
) -> List[Pool]:
"""Get pools within a TVL range."""
query = db.query(Pool).filter(Pool.tvl >= min_tvl)
if max_tvl is not None:
query = query.filter(Pool.tvl <= max_tvl)
return query.order_by(desc(Pool.tvl)).offset(skip).limit(limit).all()
def get_pools_with_dex(
self, db: Session, *, skip: int = 0, limit: int = 100
) -> List[Tuple[Pool, Dex]]:
"""Get pools with their DEX information."""
return db.query(
Pool, Dex
).join(
Dex, Pool.dex_id == Dex.id
).order_by(
desc(Pool.tvl)
).offset(skip).limit(limit).all()
def update_reserves(
self, db: Session, *, pool_id: int,
token_a_reserve: float, token_b_reserve: float,
slot: int, tvl: Optional[float] = None
) -> Optional[Pool]:
"""Update token reserves for a pool."""
db_obj = db.query(Pool).filter(Pool.id == pool_id).first()
if db_obj and slot >= db_obj.last_updated_slot:
db_obj.token_a_reserve = token_a_reserve
db_obj.token_b_reserve = token_b_reserve
db_obj.last_updated_slot = slot
if tvl is not None:
db_obj.tvl = tvl
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def get_most_active_pools(
self, db: Session, *, limit: int = 20
) -> List[Pool]:
"""Get the most active pools by volume."""
return db.query(Pool).order_by(
desc(Pool.volume_24h)
).limit(limit).all()
# Create a single instance for use in dependency injection
pool = CRUDPool(Pool)