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

Calculate LTV #322

Merged
merged 2 commits into from
Dec 4, 2024
Merged
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
2 changes: 1 addition & 1 deletion web_app/api/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions web_app/api/serializers/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
...,
Expand Down
24 changes: 18 additions & 6 deletions web_app/contract_tools/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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:
"""
Expand Down Expand Up @@ -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:
Expand Down
48 changes: 36 additions & 12 deletions web_app/contract_tools/mixins/health_ratio.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -89,46 +90,69 @@ 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(
amount * Decimal(prices[token])
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 )
# ))
Loading