From e7fa5dad6df0ee18594c9d24757b642f3e42a296 Mon Sep 17 00:00:00 2001 From: starksama <257340800+starksama@users.noreply.github.com> Date: Fri, 20 Feb 2026 23:05:58 +0800 Subject: [PATCH] feat: Add Days to Liquidation column to borrowers table Calculates days to liquidation using: - Current LTV from borrow/collateral ratio - Market's liquidation threshold (lltv) - Annual borrow rate (borrowApy) Uses continuous compounding formula: r = ln(1 + APY) Days = ln(lltv/ltv) / r * 365 - Added tooltip on header explaining the metric - Shows exact days (no cap) - Matches existing tooltip style Closes #344 --- .../components/borrowers-table.tsx | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/features/market-detail/components/borrowers-table.tsx b/src/features/market-detail/components/borrowers-table.tsx index 1d5e306f..8feaa1d2 100644 --- a/src/features/market-detail/components/borrowers-table.tsx +++ b/src/features/market-detail/components/borrowers-table.tsx @@ -44,10 +44,15 @@ export function BorrowersTable({ chainId, market, minShares, oraclePrice, onOpen const hasActiveFilter = minShares !== '0'; const tableKey = `borrowers-table-${currentPage}`; - // Calculate LTV for each borrower + // Calculate LTV and Days to Liquidation for each borrower // LTV = borrowAssets / (collateral * oraclePrice) - const borrowersWithLTV = useMemo(() => { - if (!oraclePrice || oraclePrice === 0n) return []; + // Days to Liquidation = ln(lltv/ltv) / ln(1 + borrowApy) * 365 + // (using continuous compounding: r = ln(1 + APY) to convert annual APY to continuous rate) + const borrowersWithMetrics = useMemo(() => { + if (!oraclePrice) return []; + + const lltv = Number(market.lltv) / 1e16; // lltv in WAD format (e.g., 8e17 = 80%) + const borrowApy = market.state.borrowApy; return borrowers.map((borrower) => { const borrowAssets = BigInt(borrower.borrowAssets); @@ -58,18 +63,29 @@ export function BorrowersTable({ chainId, market, minShares, oraclePrice, onOpen const collateralValueInLoan = (collateral * oraclePrice) / BigInt(10 ** 36); // Calculate LTV as a percentage - // LTV = (borrowAssets / collateralValue) * 100 let ltv = 0; if (collateralValueInLoan > 0n) { ltv = Number((borrowAssets * 10000n) / collateralValueInLoan) / 100; } + // Calculate Days to Liquidation + // Only calculate if borrower has position, LTV > 0, and borrow rate > 0 + let daysToLiquidation: number | null = null; + if (ltv > 0 && borrowApy > 0 && lltv > ltv) { + // Use continuous compounding: LTV(t) = LTV * e^(r * t) where r = ln(1 + APY) + // Solve for t when LTV(t) = lltv: t = ln(lltv/ltv) / r + const continuousRate = Math.log(1 + borrowApy); + const yearsToLiquidation = Math.log(lltv / ltv) / continuousRate; + daysToLiquidation = Math.max(0, Math.round(yearsToLiquidation * 365)); + } + return { ...borrower, ltv, + daysToLiquidation, }; }); - }, [borrowers, oraclePrice]); + }, [borrowers, oraclePrice, market.lltv, market.state.borrowApy]); return (