diff --git a/web_app/api/dashboard.py b/web_app/api/dashboard.py index 4ec6c727b..276ec1423 100644 --- a/web_app/api/dashboard.py +++ b/web_app/api/dashboard.py @@ -48,7 +48,7 @@ async def get_dashboard(wallet_id: str) -> DashboardResponse: ) # Fetch zkLend position for the wallet ID health_ratio = await HealthRatioMixin.get_health_ratio( - contract_address, first_opened_position["token_symbol"] + contract_address ) # Fetch balances (assuming you have a method for this) diff --git a/web_app/api/serializers/dashboard.py b/web_app/api/serializers/dashboard.py index 9a46ca651..4d32b02df 100644 --- a/web_app/api/serializers/dashboard.py +++ b/web_app/api/serializers/dashboard.py @@ -13,8 +13,8 @@ class DashboardResponse(BaseModel): """ DashboardResponse class for dashboard details. """ - health_ratio: str = Field( - ..., example="0.5", description="The health ratio of the user." + health_ratio: dict[str, str] = Field( + ..., example={"health_factor": "2.0", "ltv": "0.5"}, description="The health ratio of the user." ) balances: Dict[str, Any] = Field( ..., diff --git a/web_app/contract_tools/constants.py b/web_app/contract_tools/constants.py index 1343b744a..0fe022631 100644 --- a/web_app/contract_tools/constants.py +++ b/web_app/contract_tools/constants.py @@ -26,7 +26,7 @@ class TokenConfig: name: str decimals: Decimal collateral_factor: Decimal = Decimal("0.0") - debt_factor: Decimal = Decimal("0.0") + borrow_factor: Decimal = Decimal("0.0") @dataclass(frozen=True) @@ -50,21 +50,21 @@ class TokenParams: address="0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", decimals=Decimal("18"), collateral_factor=Decimal("0.80"), - debt_factor=Decimal("1"), + borrow_factor=Decimal("1"), ) STRK = TokenConfig( name="STRK", address="0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", decimals=Decimal("18"), collateral_factor=Decimal("0.50"), - debt_factor=Decimal("1"), + borrow_factor=Decimal("1"), ) USDC = TokenConfig( name="USDC", address="0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", decimals=Decimal("6"), collateral_factor=Decimal("0.80"), - debt_factor=Decimal("1"), + borrow_factor=Decimal("1"), ) @classmethod @@ -86,6 +86,18 @@ def get_token_address(cls, token_name: str) -> str: return token.address raise ValueError(f"Token {token_name} not found") + @classmethod + def get_borrow_factor(cls, token_identifier): + """ + Get the borrow factor for a given token. + :param token_identifier: Token identifier: symbol or address + :return: Token borrow factor + """ + for token in cls.tokens(): + if token.address == token_identifier or token.name == token_identifier: + return token.borrow_factor + raise ValueError(f"Token {token_identifier} not found") + @classmethod def get_token_decimals(cls, token_address: str) -> int: """ @@ -113,9 +125,9 @@ def get_token_symbol(cls, token_address: str) -> str: @classmethod def get_token_collateral_factor(cls, token_identifier: str) -> Decimal: """ - Get the token collateral factor for a given token. + Get the collateral factor for a given token. :param token_identifier: Token identifier: symbol or address - :return: Token symbol + :return: Token collateral factor """ for token in cls.tokens(): if token.address == token_identifier or token.name == token_identifier: diff --git a/web_app/contract_tools/mixins/health_ratio.py b/web_app/contract_tools/mixins/health_ratio.py index 4ab22f0d0..a2974173c 100644 --- a/web_app/contract_tools/mixins/health_ratio.py +++ b/web_app/contract_tools/mixins/health_ratio.py @@ -54,6 +54,7 @@ async def _get_z_balances( token: Decimal(balance) for token, balance in zip(reserves.keys(), await asyncio.gather(*tasks)) } + print(balances) return balances @classmethod @@ -89,21 +90,39 @@ async def _get_pragma_prices(cls, tokens: set) -> dict[str, Decimal]: token: price for token, price in zip(tokens, await asyncio.gather(*tasks)) } + @classmethod + def _get_ltv(cls, borrowed_token: str, debt_usdc: Decimal, collateral_value_usdc: Decimal): + borrow_factor = TokenParams.get_borrow_factor(borrowed_token) + return (debt_usdc / borrow_factor) / collateral_value_usdc + + @classmethod + async def _get_borrowed_token( + cls, deposit_contract_address: str + ) -> tuple[str, int]: + """ + :return: Tuple with borrowed token and current debt on ZkLend + """ + tasks = [CLIENT.get_zklend_debt(deposit_contract_address, token.address) for token in TokenParams.tokens()] + non_zero_debt = [ + (token.address, debt[0]) for token, debt in (zip(TokenParams.tokens(), await asyncio.gather(*tasks))) + if debt[0] != 0 + ] + return non_zero_debt[0] + @classmethod async def get_health_ratio( - cls, deposit_contract_address: str, borrowed_token: str - ) -> str: + cls, deposit_contract_address: str + ) -> dict[str, str]: """ Calculate the health ratio of a deposit contract. :param deposit_contract_address: The address of the deposit contract. - :param borrowed_token: The symbol of the borrowed token. + :param borrowed_token: The symbol of the borrowed token. Defaults to USDC. :return: The health ratio as a string. """ + borrowed_token_address, debt_raw = await cls._get_borrowed_token(deposit_contract_address) + borrowed_token = TokenParams.get_token_symbol(borrowed_token_address) deposits = await cls._get_deposited_tokens(deposit_contract_address) - debt_raw = await CLIENT.get_zklend_debt( - deposit_contract_address, TokenParams.get_token_address(borrowed_token) - ) prices = await cls._get_pragma_prices(set(deposits.keys()) | {borrowed_token}) deposit_usdc = sum( @@ -111,24 +130,29 @@ async def get_health_ratio( for token, amount in deposits.items() if amount != 0 ) + borrowed_address = TokenParams.get_token_address(borrowed_token) debt_usdc = ( - debt_raw[0] + debt_raw * prices[borrowed_token] / 10 ** int(TokenParams.get_token_decimals(borrowed_address)) ) - - return ( - f"{round(deposit_usdc / Decimal(debt_usdc), 2)}" if debt_usdc != 0 else "0" - ) + return { + "health_factor": f"{round(deposit_usdc / Decimal(debt_usdc), 2)}" if debt_usdc != 0 else "0", + "ltv": f"{round((debt_usdc / TokenParams.get_borrow_factor(borrowed_token)) / deposit_usdc, 2)}" + } if __name__ == "__main__": print( asyncio.run( HealthRatioMixin.get_health_ratio( - "0x0582d5Bc3CcfCeF2F7aF1FdA976767B010E453fF487A7FD2ccf9df1524f4D8fC", + "0x0582d5bc3ccfcef2f7af1fda976767b010e453ff487a7fd2ccf9df1524f4d8fc", "ETH", ) ) ) + # print(asyncio.run(CLIENT.get_balance( + # "0x01b5bd713e72fdc5d63ffd83762f81297f6175a5e0a4771cdadbc1dd5fe72cb1", + # "0x43523d3d7eb62a882efff9dc1664d7ceae8fe154866f3385d9c0bf0697a2c21", 18 ) + # ))