from fastapi import APIRouter, Depends, Request, status from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from app.api.errors import from_api_error, http_error from app.auth.dependencies import get_current_user from app.db.models import User from app.db.session import get_session from app.withdrawals.service import WithdrawalError, request_withdrawal router = APIRouter(prefix="/withdrawals", tags=["withdrawals"]) class WithdrawalRequest(BaseModel): external_address: str amount_sats: int class WithdrawalResponse(BaseModel): txid: str amount_requested_sats: int amount_sent_sats: int status: str @router.post("", response_model=WithdrawalResponse, status_code=status.HTTP_201_CREATED) async def create_withdrawal( body: WithdrawalRequest, request: Request, user: User = Depends(get_current_user), session: AsyncSession = Depends(get_session), ) -> WithdrawalResponse: listener = request.app.state.electrum_listener if listener.client is None: raise http_error( status.HTTP_503_SERVICE_UNAVAILABLE, "network_unavailable", "not connected to the network, try again shortly", ) async with request.app.state.user_locks.acquire(user.id): try: withdrawal = await request_withdrawal( session, listener.client, user, body.external_address, body.amount_sats ) except WithdrawalError as exc: code = ( status.HTTP_502_BAD_GATEWAY # the network refused it, not the caller (B-07) if exc.code == "broadcast_failed" else status.HTTP_400_BAD_REQUEST ) raise from_api_error(code, exc) from exc return WithdrawalResponse( txid=withdrawal.txid, amount_requested_sats=withdrawal.amount_requested_sats, amount_sent_sats=withdrawal.amount_sent_sats, status=withdrawal.status, )