from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.db.models import User, UtxoEvent async def recompute_balance(session: AsyncSession, user_id: int) -> int: """Source of truth: sum of this user's confirmed, unspent UTXOs. Updates and returns the read-cache column (User.cached_balance_sats). Must be called within the same transaction as whatever inserted/updated utxo_events rows.""" balance = await session.scalar( select(func.sum(UtxoEvent.amount_sats)).where(UtxoEvent.user_id == user_id, UtxoEvent.spent_txid.is_(None)) ) user = await session.get(User, user_id) user.cached_balance_sats = balance or 0 return user.cached_balance_sats