from sqlalchemy.orm import Session from fastapi import HTTPException, status from typing import List, Optional from app.models.wallet import Wallet, FiatAccount from app.models.user import User from app.schemas.wallet import WalletCreate, FiatAccountCreate from app.utils.crypto import WalletFactory, CryptoUtils from app.core.config import settings class WalletService: def __init__(self, db: Session): self.db = db def create_crypto_wallet(self, user: User, wallet_data: WalletCreate) -> Wallet: # Check if user already has a wallet for this currency existing_wallet = self.db.query(Wallet).filter( Wallet.user_id == user.id, Wallet.currency == wallet_data.currency.upper() ).first() if existing_wallet: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Wallet for {wallet_data.currency} already exists" ) try: # Generate wallet private_key, address = WalletFactory.create_wallet(wallet_data.currency) # Encrypt private key encryption_password = f"{user.email}_{settings.secret_key}" encrypted_private_key = CryptoUtils.encrypt_private_key(private_key, encryption_password) # Create wallet record db_wallet = Wallet( user_id=user.id, currency=wallet_data.currency.upper(), address=address, private_key_encrypted=encrypted_private_key, balance=0.0 ) self.db.add(db_wallet) self.db.commit() self.db.refresh(db_wallet) return db_wallet except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to create wallet: {str(e)}" ) def create_fiat_account(self, user: User, account_data: FiatAccountCreate) -> FiatAccount: # Check if user already has an account for this currency existing_account = self.db.query(FiatAccount).filter( FiatAccount.user_id == user.id, FiatAccount.currency == account_data.currency.upper() ).first() if existing_account: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Fiat account for {account_data.currency} already exists" ) db_account = FiatAccount( user_id=user.id, currency=account_data.currency.upper(), balance=0.0 ) self.db.add(db_account) self.db.commit() self.db.refresh(db_account) return db_account def get_user_wallets(self, user: User) -> List[Wallet]: return self.db.query(Wallet).filter( Wallet.user_id == user.id, Wallet.is_active ).all() def get_user_fiat_accounts(self, user: User) -> List[FiatAccount]: return self.db.query(FiatAccount).filter( FiatAccount.user_id == user.id, FiatAccount.is_active ).all() def get_wallet_by_id(self, wallet_id: int, user: User) -> Optional[Wallet]: return self.db.query(Wallet).filter( Wallet.id == wallet_id, Wallet.user_id == user.id ).first() def get_fiat_account_by_id(self, account_id: int, user: User) -> Optional[FiatAccount]: return self.db.query(FiatAccount).filter( FiatAccount.id == account_id, FiatAccount.user_id == user.id ).first() def update_wallet_balance(self, wallet_id: int, new_balance: float) -> bool: wallet = self.db.query(Wallet).filter(Wallet.id == wallet_id).first() if wallet: wallet.balance = new_balance self.db.commit() return True return False def update_fiat_balance(self, account_id: int, new_balance: float) -> bool: account = self.db.query(FiatAccount).filter(FiatAccount.id == account_id).first() if account: account.balance = new_balance self.db.commit() return True return False def get_private_key(self, wallet: Wallet, user: User) -> str: try: encryption_password = f"{user.email}_{settings.secret_key}" private_key = CryptoUtils.decrypt_private_key( wallet.private_key_encrypted, encryption_password ) return private_key except Exception: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to decrypt private key" )