Automated Action ab87d3c506 Implement comprehensive cryptocurrency exchange platform
- Built complete CEX platform with FastAPI and Python
- JWT-based authentication system with secure password hashing
- Multi-currency crypto wallet support (BTC, ETH, USDT)
- Fiat account management (USD, EUR, GBP)
- Local transaction signing without external APIs
- Comprehensive transaction handling (send/receive/deposit/withdraw)
- SQLAlchemy models with Alembic migrations
- Security middleware (rate limiting, headers, logging)
- Input validation and sanitization
- Encrypted private key storage with PBKDF2
- Standardized codebase architecture with service layer pattern
- Complete API documentation with health endpoints
- Comprehensive README with setup instructions

Features:
- User registration and authentication
- Crypto wallet creation and management
- Secure transaction signing using local private keys
- Fiat deposit/withdrawal system
- Transaction history and tracking
- Rate limiting and security headers
- Input validation for all endpoints
- Error handling and logging
2025-06-20 23:08:04 +00:00

134 lines
4.8 KiB
Python

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"
)