Skip to content

Commit

Permalink
Merge branch 'main' into feat/create-user-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Oluwatos94 authored Feb 27, 2025
2 parents 1742e8b + e9cd266 commit 1570ccc
Show file tree
Hide file tree
Showing 45 changed files with 7,501 additions and 1,644 deletions.
28 changes: 28 additions & 0 deletions margin_app/app/api/deposit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
This module contains the API routes for deposit.
"""

from fastapi import APIRouter
from uuid import UUID

from app.crud.deposit import deposit_crud
from app.schemas.deposit import DepositUpdate, DepositResponse

router = APIRouter()


@router.post("/update/{deposit_id}", response_model=DepositResponse)
async def update_deposit(
deposit_id: UUID,
deposit_update: DepositUpdate,
):
"""
Update a deposit by ID.
:param deposit_id: str
:param deposit_update: DepositUpdate data
:param db: AsyncSession
:return: Deposit
"""
return await deposit_crud.update_deposit(
deposit_id, deposit_update.model_dump(exclude_none=True)
)
38 changes: 38 additions & 0 deletions margin_app/app/api/liquidation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
This module contains endpoints for managing liquidations.
"""

from uuid import UUID
from decimal import Decimal
from fastapi import HTTPException
from app.crud.liquidation import liquidation_crud # Using the instance from the specified module
from app.schemas.liquidation import LiquidationResponse

async def liquidate_position(
margin_position_id: UUID,
bonus_amount: Decimal,
bonus_token: str,
) -> LiquidationResponse:
"""
Liquidates a margin position by creating a liquidation record.
Args:
margin_position_id (UUID): The ID of the margin position.
bonus_amount (Decimal): The bonus amount applied.
bonus_token (str): The token used for the bonus.
Returns:
LiquidationResponse: Details of the liquidation entry.
"""
try:
liquidation_entry = await liquidation_crud.liquidate_position(
margin_position_id, bonus_amount, bonus_token
)
return LiquidationResponse(
margin_position_id=liquidation_entry.margin_position_id,
bonus_amount=liquidation_entry.bonus_amount,
bonus_token=liquidation_entry.bonus_token,
status="success",
)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
31 changes: 31 additions & 0 deletions margin_app/app/api/margin_position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
This module contains the API routes for margin positions.
"""

from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession

from app.crud.margin_position import margin_position_crud
from app.schemas.margin_position import MarginPositionCreate, MarginPositionResponse

router = APIRouter()


@router.post("/open_margin_position", response_model=MarginPositionResponse)
async def open_margin_position(
position_data: MarginPositionCreate,
db: AsyncSession = Depends(margin_position_crud.session),
):
"""
Opens a margin position by creating an entry record in the database.
:param position_data: MarginPositionCreate
:param db: AsyncSession
:return: MarginPositionResponse
"""
position = await margin_position_crud.open_margin_position(
user_id=position_data.user_id,
borrowed_amount=position_data.borrowed_amount,
multiplier=position_data.multiplier,
transaction_id=position_data.transaction_id,
)
return position
77 changes: 75 additions & 2 deletions margin_app/app/api/pools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,55 @@
This module contains the API routes for the pools.
"""

from fastapi import APIRouter, HTTPException, status
from fastapi import APIRouter, HTTPException, status, Depends
from loguru import logger
from sqlalchemy.ext.asyncio import AsyncSession

from app.crud.pool import pool_crud
from app.crud.pool import user_pool_crud
from app.schemas.pools import UserPoolResponse, UserPoolCreate
from app.schemas.pools import (
UserPoolResponse,
UserPoolCreate,
UserPoolUpdateResponse,
UserPoolUpdate,
PoolCreate,
PoolResponse,
PoolRiskStatus,
)
from app.db.sessions import get_db

router = APIRouter()


@router.post(
"/create_pool", response_model=PoolResponse, status_code=status.HTTP_201_CREATED
)
async def create_pool(token: str, risk_status: PoolRiskStatus) -> PoolResponse:
"""
Create a new pool
:param token: pool token (path parameter)
:param risk_status: pool risk status
:param db: database session
:return: created pool
"""
try:
created_pool = await pool_crud.create_pool(token=token, risk_status=risk_status)
if not created_pool:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Pool was not created.",
)
except Exception as e:
logger.error(f"Error creating pool: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Something went wrong.",
) from e

return created_pool


@router.post(
"/create_user_pool",
response_model=UserPoolResponse,
Expand All @@ -37,3 +77,36 @@ async def create_user_pool(user_pool: UserPoolCreate) -> UserPoolResponse:
) from e

return proposal


@router.post(
"/update_user_pool",
response_model=UserPoolUpdateResponse,
status_code=status.HTTP_200_OK,
)
async def update_user_pool(user_pool: UserPoolUpdate) -> UserPoolUpdateResponse:
"""
Update an existing user pool entry.
:param user_pool: user pool id and amount to update.
:return: Updated user pool entry.
"""
try:
updated_pool = await user_pool_crud.update_user_pool(
user_pool_id=user_pool.user_pool_id, amount=user_pool.amount
)

if not updated_pool:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User pool entry not found.",
)

except Exception as e:
logger.error(f"Error updating user pool: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Something went wrong while updating the user pool.",
) from e

return updated_pool
34 changes: 30 additions & 4 deletions margin_app/app/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"""
from fastapi import APIRouter,status, HTTPException
from loguru import logger
from ..crud.user import user_crud as crud_create_user
from app.schemas.user import UserResponse, UserCreate
from app.crud.user import user_crud as crud_create_user
from app.crud.deposit import deposit_crud
from app.schemas.user import UserResponse, UserCreate, AddUserDepositRequest, AddUserDepositResponse

router = APIRouter()

Expand All @@ -29,9 +30,34 @@ async def create_user(user: UserCreate)-> UserResponse:
try:
user = await crud_create_user.create_user(user.wallet_id)
except Exception as e:
logger.error(f"Error creating user pool: {e}")
logger.error(f"Error creating user: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Something went wrong.",
) from e
return user
return user


@router.post(
"/add_user_deposit",
status_code=status.HTTP_201_CREATED,
response_model=AddUserDepositResponse,
)
async def add_user_deposit(user_deposit: AddUserDepositRequest):
"""
Add an user deposit
:param user_deposit: user id, amount, token, transaction_id
:return: deposit id
"""
try:
deposit = await deposit_crud.create_deposit(
user_id=user_deposit.user_id,
token=user_deposit.token,
amount=user_deposit.amount,
transaction_id=user_deposit.transaction_id,
)
return AddUserDepositResponse(deposit_id=deposit.id)
except Exception as e:
logger.error(f"Error adding user deposit: {e}")
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=str(e)) from e
5 changes: 2 additions & 3 deletions margin_app/app/crud/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from typing import Type, TypeVar
from app.models.base import BaseModel

from typing import AsyncIterator
from typing import AsyncIterator, Callable
from sqlalchemy import select
from sqlalchemy.exc import SQLAlchemyError
from contextlib import asynccontextmanager
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine, AsyncSession
from app.core.config import settings

logger = logging.getLogger(__name__)
ModelType = TypeVar("ModelType", bound=BaseModel)

Expand All @@ -36,7 +35,7 @@ def __init__(self):
"""
self.engine = create_async_engine(settings.db_url)
self.session_maker = async_sessionmaker(bind=self.engine)

@asynccontextmanager
async def session(self) -> AsyncIterator[AsyncSession]:
"""
Expand Down
11 changes: 6 additions & 5 deletions margin_app/app/crud/liquidation.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
"""This module contains the LiquidationCRUD class for managing liquidations."""

from app.crud.base import DBConnector
from app.models.liquidation import Liquidation
from uuid import UUID
from decimal import Decimal

from app.crud.base import DBConnector
from app.models.liquidation import Liquidation

class LiquidationCRUD(DBConnector):
"""Handles database operations for liquidations."""

async def liquidate_position(
self, margin_position_id: UUID,
self, margin_position_id: UUID,
bonus_amount: Decimal,
bonus_token: str
) -> Liquidation:
"""
Liquidates a position by creating a liquidation record in the database.
:param position_id: ID of the position to be liquidated.
:param margin_position_id: UUID of the position to be liquidated.
:param bonus_amount: Decimal
:param bonus_token: str
:return: The created Liquidation record.
Expand All @@ -28,4 +29,4 @@ async def liquidate_position(
)
return await self.write_to_db(liquidation_entry)

liqudation_crud = LiquidationCRUD()
liquidation_crud = LiquidationCRUD()
1 change: 1 addition & 0 deletions margin_app/app/crud/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ async def create_pool(self, token: str, risk_status: PoolRiskStatus) -> Pool:
"""
Creates a new pool
:param token: string of the token in the pool
:param risk_status: risk status of the pool
:return Pool the object successfully added to the database
"""
pool_entry: Pool = Pool(token=token, risk_status=risk_status)
Expand Down
18 changes: 13 additions & 5 deletions margin_app/app/crud/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import Optional
from uuid import UUID
from sqlalchemy.sql import text
from sqlalchemy.exc import IntegrityError
from decimal import Decimal

from app.models.deposit import Deposit
Expand All @@ -29,28 +30,30 @@ async def test_connection(self):
async with self.session() as session:
result = await session.execute(text("SELECT version()"))
return f"PostgreSQL version: {result.scalar()}"


async def create_user(self, wallet_id: str) -> User:
"""
Create a new user in the database.
:param wallet_id: str
:return: User
"""

new_user = User(wallet_id=wallet_id)
return await self.write_to_db(new_user)


async def update_user(self, user_id: UUID, **kwargs) -> Optional[User]:
"""
Update an existing user in the database.
:param user_id: UUID
:return: User
"""

with self.session() as session:
async with self.session() as session:
user = await session.get(User, user_id)
if not user:
return None

for key, value in kwargs.items():
setattr(user, key, value)
await session.commit()
Expand All @@ -63,7 +66,6 @@ async def delete_user(self, user_id: UUID) -> None:
:param user_id: UUID
:return: None
"""

await self.delete_object_by_id(User, user_id)

async def add_deposit(
Expand All @@ -81,12 +83,17 @@ async def add_deposit(

if not await self.get_object(User, user_id):
raise ValueError(f"User {user_id} does not exist.")

new_deposit = Deposit(
user_id=user_id, amount=amount,
token=token, transaction_id=transaction_id
user_id=user_id,
amount=amount,
token=token,
transaction_id=transaction_id
)
return await self.write_to_db(new_deposit)



async def add_margin_position(
self, user_id: UUID,
borrowed_amount: Decimal,
Expand All @@ -112,4 +119,5 @@ async def add_margin_position(
)
return await self.write_to_db(new_margin_position)


user_crud = UserCRUD()
Loading

0 comments on commit 1570ccc

Please sign in to comment.