Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculated TVL amount #159

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions web_app/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,48 @@ async def get_user_contract_address(wallet_id: str) -> GetUserContractAddressRes
response_description="Total amount for all open positions across all users & \
Number of unique users in the database.",
)
async def get_stats() -> GetStatsResponse:
"""
Retrieves the total amount for open positions and the count of unique users.
async def get_stats() -> GetStatsResponse:
"""
Retrieves the total amount for open positions converted to USDC
and the count of unique users.
### Returns:
- total_opened_amount: Sum of amounts for all open positions.
- unique_users: Total count of unique users.
- total_opened_amount: Sum of amounts for all open positions in USDC.
- unique_users: Total count of unique users.
"""
try:
total_opened_amount = position_db.get_total_amounts_for_open_positions()
# Fetch open positions amounts by token
token_amounts = position_db.get_total_amounts_for_open_positions()

# Fetch current prices
current_prices = await position_db.get_current_prices()

# Convert all token amounts to USDC
total_opened_amount = Decimal('0')
for token, amount in token_amounts.items():
# Skip if no price available for the token
if token not in current_prices or 'USDC' not in current_prices:
logger.warning(f"No price data available for {token}")
continue

# If the token is USDC, use it directly
if token == 'USDC':
total_opened_amount += amount
continue

# Convert other tokens to USDC
# Price is typically in USDC per token
usdc_price = current_prices[token]
usdc_equivalent = amount * Decimal(usdc_price)
total_opened_amount += usdc_equivalent

unique_users = user_db.get_unique_users_count()

return GetStatsResponse(
total_opened_amount=total_opened_amount, unique_users=unique_users
total_opened_amount=total_opened_amount,
unique_users=unique_users
)

except AttributeError as e:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove this code?

raise HTTPException(status_code=500, detail=f"AttributeError: {str(e)}")
except TypeError as e:
raise HTTPException(status_code=500, detail=f"TypeError: {str(e)}")

except Exception as e:
logger.error(f"Error in get_stats: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
48 changes: 24 additions & 24 deletions web_app/contract_tools/mixins/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,33 @@ class DashboardMixin:
"""

@classmethod
async def get_current_prices(cls) -> Dict[str, str]:
"""
Fetch current token prices from AVNU API.
:return: Returns dictionary mapping token symbols to their current prices.
async def get_current_prices(cls) -> Dict[str, Decimal]:
"""
Fetch current token prices from AVNU API.
:return: Returns dictionary mapping token symbols to their current prices as Decimal.
"""
prices = {}

response = await APIRequest(base_url=AVNU_PRICE_URL).fetch("")
if not response:
try:
response = await APIRequest(base_url=AVNU_PRICE_URL).fetch("")
if not response:
return prices

for token_data in response:
try:
address = token_data.get("address")
current_price = token_data.get("currentPrice")
if address and current_price is not None:
symbol = TokenParams.get_token_symbol(address)
if symbol:
# Convert to Decimal for precise calculations
prices[symbol] = Decimal(str(current_price))
except (AttributeError, TypeError, ValueError) as e:
logger.info(f"Error parsing price for {address}: {str(e)}")

return prices
except Exception as e:
logger.error(f"Error fetching current prices: {e}")
return prices

for token_data in response:
try:
address = token_data.get("address")
current_price = token_data.get("currentPrice")
if address and current_price is not None:
symbol = TokenParams.get_token_symbol(address)
if symbol:
prices[symbol] = str(Decimal(current_price))
except AttributeError as e:
logger.info(f"AttributeError while parsing price for {address}: {str(e)}")
except TypeError as e:
logger.info(f"TypeError while parsing price for {address}: {str(e)}")
except ValueError as e:
logger.info(f"ValueError while parsing price for {address}: {str(e)}")

return prices

@classmethod
async def get_wallet_balances(cls, holder_address: str) -> Dict[str, str]:
Expand Down
31 changes: 20 additions & 11 deletions web_app/db/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,23 +362,32 @@ def open_position(self, position_id: uuid.UUID, current_prices: dict) -> str | N
logger.error(f"Position with ID {position_id} not found")
return None

def get_total_amounts_for_open_positions(self) -> Decimal:
"""
Calculates the total amount for all positions where status is 'OPENED'.

:return: Total amount for all opened positions
def get_total_amounts_for_open_positions(self) -> dict[str, Decimal]:
"""
Calculates the amounts for all positions where status is 'OPENED',
grouped by token symbol.

:return: Dictionary of total amounts for each token in opened positions
"""
with self.Session() as db:
try:
total_opened_amount = (
db.query(func.sum(cast(Position.amount, Numeric)))
# Group by token symbol and sum amounts
token_amounts = (
db.query(
Position.token,
func.sum(cast(Position.amount, Numeric)).label('total_amount')
)
.filter(Position.status == Status.OPENED.value)
.scalar()
.group_by(Position.token)
.all()
)
return total_opened_amount

# Convert to dictionary
return {token: Decimal(str(amount)) for token, amount in token_amounts}

except SQLAlchemyError as e:
logger.error(f"Error calculating total amount for open positions: {e}")
return Decimal(0.0)
logger.error(f"Error calculating amounts for open positions: {e}")
return {}

def save_current_price(self, position: Position, price_dict: dict) -> None:
"""
Expand Down
Loading