from typing import Any, List from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app import crud, models, schemas from app.api import deps from app.models.transaction import TransactionType router = APIRouter() @router.get("/", response_model=List[schemas.Wallet]) def read_wallets( current_user: models.User = Depends(deps.get_current_active_verified_user), db: Session = Depends(deps.get_db), ) -> Any: """ Retrieve user's wallets. """ wallets = crud.wallet.get_by_user(db, user_id=current_user.id) return wallets @router.get("/{wallet_type}", response_model=schemas.Wallet) def read_wallet( wallet_type: schemas.WalletType, current_user: models.User = Depends(deps.get_current_active_verified_user), db: Session = Depends(deps.get_db), ) -> Any: """ Get a specific wallet by type. """ wallet = crud.wallet.get_by_user_and_type( db, user_id=current_user.id, wallet_type=wallet_type ) if not wallet: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Wallet of type {wallet_type} not found", ) return wallet @router.post("/transfer", response_model=dict) def transfer_funds( *, transfer_data: schemas.WalletTransfer, current_user: models.User = Depends(deps.get_current_active_verified_user), db: Session = Depends(deps.get_db), ) -> Any: """ Transfer funds between wallets. """ if transfer_data.from_wallet_type == transfer_data.to_wallet_type: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot transfer between the same wallet type", ) from_wallet = crud.wallet.get_by_user_and_type( db, user_id=current_user.id, wallet_type=transfer_data.from_wallet_type ) if not from_wallet: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Source wallet of type {transfer_data.from_wallet_type} not found", ) if from_wallet.balance < transfer_data.amount: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Insufficient funds in source wallet", ) to_wallet = crud.wallet.get_by_user_and_type( db, user_id=current_user.id, wallet_type=transfer_data.to_wallet_type ) if not to_wallet: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Destination wallet of type {transfer_data.to_wallet_type} not found", ) from_wallet, to_wallet = crud.wallet.transfer( db, user_id=current_user.id, from_type=transfer_data.from_wallet_type, to_type=transfer_data.to_wallet_type, amount=transfer_data.amount, ) if not from_wallet or not to_wallet: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Transfer failed", ) # Create transfer transaction records # First, create the outgoing transaction outgoing_transaction = crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=current_user.id, wallet_id=from_wallet.id, amount=-transfer_data.amount, transaction_type=TransactionType.TRANSFER, description=f"Transfer to {transfer_data.to_wallet_type} wallet", ), ) # Then, create the incoming transaction incoming_transaction = crud.transaction.create( db, obj_in=schemas.TransactionCreate( user_id=current_user.id, wallet_id=to_wallet.id, amount=transfer_data.amount, transaction_type=TransactionType.TRANSFER, description=f"Transfer from {transfer_data.from_wallet_type} wallet", related_transaction_id=outgoing_transaction.id, ), ) # Update the related transaction ID for the outgoing transaction crud.transaction.update( db, db_obj=outgoing_transaction, obj_in={"related_transaction_id": incoming_transaction.id}, ) return { "message": f"Successfully transferred {transfer_data.amount} USDT from {transfer_data.from_wallet_type} wallet to {transfer_data.to_wallet_type} wallet", "from_wallet": { "type": from_wallet.wallet_type, "balance": from_wallet.balance, }, "to_wallet": { "type": to_wallet.wallet_type, "balance": to_wallet.balance, }, }