feat: select liquidable loans
This commit is contained in:
parent
ccc78fc6ae
commit
db67a387d6
|
@ -27,11 +27,14 @@ export const LABELS = {
|
|||
BORROW_QUESTION: "How much would you like to borrow?",
|
||||
BORROW_ACTION: "Borrow",
|
||||
LIQUIDATE_ACTION: "Liquidate",
|
||||
LIQUIDATE_INFO: "Connect to a wallet to view liquidable loans.",
|
||||
LIQUIDATE_NO_LOANS: "There are no loans to liquidate with your wallet.",
|
||||
TABLE_TITLE_ASSET: "Asset",
|
||||
TABLE_TITLE_YOUR_LOAN_BALANCE: "Your loan balance",
|
||||
TABLE_TITLE_LOAN_BALANCE: "Loan balance",
|
||||
TABLE_TITLE_DEPOSIT_BALANCE: "Your deposit balance",
|
||||
TABLE_TITLE_APY: "APY",
|
||||
TABLE_TITLE_LTV: "LTV",
|
||||
TABLE_TITLE_BORROW_APY: "Borrow APY",
|
||||
TABLE_TITLE_DEPOSIT_APY: "Deposit APY",
|
||||
TABLE_TITLE_TOTAL_BORROWED: "Total Borrowed",
|
||||
|
|
|
@ -10,3 +10,4 @@ export * from "./useUserObligationByReserve";
|
|||
export * from "./useBorrowedAmount";
|
||||
export * from "./useUserDeposits";
|
||||
export * from "./useSliderInput";
|
||||
export * from "./useLiquidableObligations";
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import { useMemo } from "react";
|
||||
import { useUserAccounts } from "./useUserAccounts";
|
||||
import { useLendingObligations } from "./useLendingObligations";
|
||||
import { LendingReserve } from "../models/lending";
|
||||
import { useLendingReserves } from "./useLendingReserves";
|
||||
import { ParsedAccount } from "../contexts/accounts";
|
||||
|
||||
export const useLiquidableObligations = () => {
|
||||
const { userAccounts } = useUserAccounts();
|
||||
const { obligations } = useLendingObligations();
|
||||
const { reserveAccounts } = useLendingReserves();
|
||||
|
||||
const availableReserves = useMemo(() => {
|
||||
return reserveAccounts.reduce((map, reserve) => {
|
||||
if (userAccounts.some(acc => acc.info.mint.toBase58() === reserve.info.liquidityMint.toBase58())) {
|
||||
map.set(reserve.pubkey.toBase58(), reserve);
|
||||
}
|
||||
return map;
|
||||
}, new Map<string, ParsedAccount<LendingReserve>>())
|
||||
}, [reserveAccounts, userAccounts])
|
||||
|
||||
const liquidableObligations = useMemo(() => {
|
||||
if (availableReserves.size === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return obligations
|
||||
.map(obligation => (
|
||||
{
|
||||
obligation,
|
||||
reserve: availableReserves.get(obligation.info.borrowReserve.toBase58()) as ParsedAccount<LendingReserve>
|
||||
}
|
||||
))
|
||||
.filter(item => item.reserve)
|
||||
.map(item => {
|
||||
// TODO: calculate LTV
|
||||
const ltv = 81;
|
||||
const liquidationThreshold = item.reserve.info.config.liquidationThreshold;
|
||||
const health = (ltv - liquidationThreshold) / liquidationThreshold
|
||||
return {
|
||||
obligation: item.obligation,
|
||||
ltv,
|
||||
liquidationThreshold,
|
||||
health
|
||||
}
|
||||
})
|
||||
.filter(item => item.ltv > item.liquidationThreshold)
|
||||
.sort((a, b) => b.health - a.health);
|
||||
}, [obligations, availableReserves]);
|
||||
|
||||
return {
|
||||
liquidableObligations
|
||||
};
|
||||
}
|
|
@ -1,44 +1,36 @@
|
|||
import { PublicKey } from "@solana/web3.js";
|
||||
import BN from "bn.js";
|
||||
import React from "react";
|
||||
import { LABELS, ZERO } from "../../constants";
|
||||
import { LABELS } from "../../constants";
|
||||
import { LiquidateItem } from "./item";
|
||||
import "./itemStyle.less";
|
||||
import { useLiquidableObligations } from "./../../hooks";
|
||||
import { useWallet } from "../../contexts/wallet";
|
||||
import "./style.less";
|
||||
|
||||
export const LiquidateView = () => {
|
||||
const { liquidableObligations } = useLiquidableObligations();
|
||||
const { connected } = useWallet();
|
||||
|
||||
// ParsedAccount<LendingObligation>
|
||||
const obligations = [
|
||||
{
|
||||
pubkey: new PublicKey("2KfJP7pZ6QSpXa26RmsN6kKVQteDEdQmizLSvuyryeiW"),
|
||||
account: {
|
||||
executable: false,
|
||||
owner: new PublicKey("2KfJP7pZ6QSpXa26RmsN6kKVQteDEdQmizLSvuyryeiW"),
|
||||
lamports: 0,
|
||||
data: new Buffer("x"),
|
||||
},
|
||||
info: {
|
||||
lastUpdateSlot: ZERO,
|
||||
collateralAmount: ZERO,
|
||||
collateralSupply: new PublicKey("2KfJP7pZ6QSpXa26RmsN6kKVQteDEdQmizLSvuyryeiW"),
|
||||
cumulativeBorrowRateWad: ZERO,
|
||||
borrowAmountWad: new BN(0),
|
||||
borrowReserve: new PublicKey("EwhnKnkwcAeVxHDbR5wMpjwipHFuafxTUhQaaagjUxQG"),
|
||||
tokenMint: new PublicKey("2KfJP7pZ6QSpXa26RmsN6kKVQteDEdQmizLSvuyryeiW"),
|
||||
}
|
||||
}
|
||||
];
|
||||
return (
|
||||
<div className="flexColumn">
|
||||
<div className="liquidate-item liquidate-header">
|
||||
<div>{LABELS.TABLE_TITLE_ASSET}</div>
|
||||
<div>{LABELS.TABLE_TITLE_LOAN_BALANCE}</div>
|
||||
<div>{LABELS.TABLE_TITLE_APY}</div>
|
||||
<div>{LABELS.TABLE_TITLE_ACTION}</div>
|
||||
</div>
|
||||
{obligations.map((obligation) => (
|
||||
<LiquidateItem key={obligation.pubkey.toBase58()} obligation={obligation}></LiquidateItem>
|
||||
))}
|
||||
<div className="liquidate-container">
|
||||
{!connected && (
|
||||
<div className="liquidate-info">{LABELS.LIQUIDATE_INFO}</div>
|
||||
)}
|
||||
{connected && liquidableObligations.length === 0 && (
|
||||
<div className="liquidate-info">{LABELS.LIQUIDATE_NO_LOANS}</div>
|
||||
)}
|
||||
{connected && liquidableObligations.length > 0 && (
|
||||
<div className="flexColumn">
|
||||
<div className="liquidate-item liquidate-header">
|
||||
<div>{LABELS.TABLE_TITLE_ASSET}</div>
|
||||
<div>{LABELS.TABLE_TITLE_LOAN_BALANCE}</div>
|
||||
<div>{LABELS.TABLE_TITLE_APY}</div>
|
||||
<div>{LABELS.TABLE_TITLE_LTV}</div>
|
||||
<div>{LABELS.TABLE_TITLE_ACTION}</div>
|
||||
</div>
|
||||
{liquidableObligations.map((item) => (
|
||||
<LiquidateItem key={item.obligation.pubkey.toBase58()} obligation={item.obligation} ltv={item.ltv}></LiquidateItem>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useMemo } from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { cache, ParsedAccount, useMint } from "../../contexts/accounts";
|
||||
import { LendingObligation, LendingReserve, calculateBorrowAPY } from "../../models/lending";
|
||||
import { useTokenName } from "../../hooks";
|
||||
|
@ -15,16 +15,15 @@ import { LABELS } from "../../constants";
|
|||
|
||||
export const LiquidateItem = (props: {
|
||||
obligation: ParsedAccount<LendingObligation>;
|
||||
ltv: number
|
||||
}) => {
|
||||
|
||||
const { obligation } = props;
|
||||
const { obligation, ltv } = props;
|
||||
|
||||
const borrowReserve = cache.get(obligation.info.borrowReserve) as ParsedAccount<LendingReserve>;
|
||||
const tokenName = useTokenName(borrowReserve?.info.liquidityMint);
|
||||
const liquidityMint = useMint(borrowReserve.info.liquidityMint);
|
||||
|
||||
console.log("wad",obligation.info.borrowAmountWad)
|
||||
|
||||
const borrowAmount = fromLamports(
|
||||
wadToLamports(obligation.info.borrowAmountWad),
|
||||
liquidityMint
|
||||
|
@ -35,7 +34,7 @@ export const LiquidateItem = (props: {
|
|||
]);
|
||||
|
||||
return (
|
||||
<Link to={`/liquidate/${obligation.pubkey.toBase58()}`}>
|
||||
<Link to={`/liquidate/${borrowReserve.pubkey.toBase58()}`}>
|
||||
<Card>
|
||||
<div className="liquidate-item">
|
||||
<span style={{ display: "flex" }}>
|
||||
|
@ -48,6 +47,9 @@ export const LiquidateItem = (props: {
|
|||
<div>
|
||||
{formatPct.format(borrowAPY)}
|
||||
</div>
|
||||
<div>
|
||||
{formatPct.format(ltv / 100)}
|
||||
</div>
|
||||
<div>
|
||||
<Button>
|
||||
<span>{LABELS.LIQUIDATE_ACTION}</span>
|
||||
|
|
|
@ -26,4 +26,18 @@
|
|||
text-align: left;
|
||||
flex: 80px
|
||||
}
|
||||
}
|
||||
|
||||
.liquidate-info {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.liquidate-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
}
|
Loading…
Reference in New Issue