mirror of https://github.com/certusone/oyster.git
feat: add liquidity chart
This commit is contained in:
parent
31020e7e86
commit
f9adc64ca9
|
@ -20,4 +20,5 @@ Any content produced by Solana, or developer resources that Solana provides, are
|
|||
- [] Add market size on front page
|
||||
- [] Add github link
|
||||
- [] Repay from reserve (add selection for obligation/loan)
|
||||
- []
|
||||
- [] Add support for token names in URL in addition to reserve address
|
||||
|
||||
|
|
|
@ -76,8 +76,8 @@ export const repay = async (
|
|||
signers
|
||||
);
|
||||
|
||||
const loanRatio = amountLamports / wadToLamports(obligation.info.borrowAmountWad)
|
||||
.toNumber();
|
||||
const loanRatio =
|
||||
amountLamports / wadToLamports(obligation.info.borrowAmountWad).toNumber();
|
||||
console.log(loanRatio);
|
||||
|
||||
// create approval for transfer transactions
|
||||
|
|
|
@ -84,9 +84,7 @@ export const BorrowInput = (props: {
|
|||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
<div className="borrow-input-title">
|
||||
{LABELS.BORROW_QUESTION}
|
||||
</div>
|
||||
<div className="borrow-input-title">{LABELS.BORROW_QUESTION}</div>
|
||||
<div className="token-input">
|
||||
<TokenIcon mintAddress={borrowReserve?.liquidityMint} />
|
||||
<NumericInput
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import { Button } from "antd"
|
||||
import { ButtonProps } from "antd/lib/button"
|
||||
import React from "react"
|
||||
import { Button } from "antd";
|
||||
import { ButtonProps } from "antd/lib/button";
|
||||
import React from "react";
|
||||
import { useWallet } from "../../contexts/wallet";
|
||||
import { LABELS } from './../../constants';
|
||||
import { LABELS } from "./../../constants";
|
||||
|
||||
export const ConnectButton = (props: ButtonProps & React.RefAttributes<HTMLElement>) => {
|
||||
export const ConnectButton = (
|
||||
props: ButtonProps & React.RefAttributes<HTMLElement>
|
||||
) => {
|
||||
const { wallet, connected } = useWallet();
|
||||
const { onClick, children, ...rest } = props;
|
||||
return <Button {...rest} onClick={connected ? onClick : wallet.connect} >
|
||||
return (
|
||||
<Button {...rest} onClick={connected ? onClick : wallet.connect}>
|
||||
{connected ? props.children : LABELS.CONNECT_LABEL}
|
||||
</Button>
|
||||
}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -36,9 +36,7 @@ export const AppLayout = (props: any) => {
|
|||
return (
|
||||
<div className="App">
|
||||
<div className="Banner">
|
||||
<div className="Banner-description">
|
||||
{LABELS.AUDIT_WARNING}
|
||||
</div>
|
||||
<div className="Banner-description">{LABELS.AUDIT_WARNING}</div>
|
||||
</div>
|
||||
<BasicLayout
|
||||
title={LABELS.APP_TITLE}
|
||||
|
|
|
@ -14,7 +14,12 @@ import { useWallet } from "../../contexts/wallet";
|
|||
import { repay } from "../../actions";
|
||||
import { CollateralSelector } from "./../CollateralSelector";
|
||||
import "./style.less";
|
||||
import { wadToLamports, formatNumber, fromLamports, toLamports } from "../../utils/utils";
|
||||
import {
|
||||
wadToLamports,
|
||||
formatNumber,
|
||||
fromLamports,
|
||||
toLamports,
|
||||
} from "../../utils/utils";
|
||||
import { LABELS } from "../../constants";
|
||||
|
||||
export const RepayInput = (props: {
|
||||
|
@ -50,9 +55,14 @@ export const RepayInput = (props: {
|
|||
|
||||
const obligationAccount = useAccountByMint(obligation?.info.tokenMint);
|
||||
|
||||
const lamports = useMemo(() => toLamports(parseFloat(value), repayLiquidityMint), [value, repayLiquidityMint]);
|
||||
const lamports = useMemo(
|
||||
() => toLamports(parseFloat(value), repayLiquidityMint),
|
||||
[value, repayLiquidityMint]
|
||||
);
|
||||
|
||||
const mark = wadToLamports(obligation?.info.borrowAmountWad).toNumber() / lamports * 100;
|
||||
const mark =
|
||||
(wadToLamports(obligation?.info.borrowAmountWad).toNumber() / lamports) *
|
||||
100;
|
||||
|
||||
const onRepay = useCallback(() => {
|
||||
if (
|
||||
|
@ -103,8 +113,8 @@ export const RepayInput = (props: {
|
|||
}}
|
||||
>
|
||||
<div className="repay-input-title">
|
||||
{LABELS.REPAY_QUESTION} (Currently:{" "})
|
||||
{formatNumber.format(balance)} {name})
|
||||
{LABELS.REPAY_QUESTION} (Currently: ){formatNumber.format(balance)}{" "}
|
||||
{name})
|
||||
</div>
|
||||
<div className="token-input">
|
||||
<TokenIcon mintAddress={repayReserve?.info.liquidityMint} />
|
||||
|
@ -124,10 +134,22 @@ export const RepayInput = (props: {
|
|||
/>
|
||||
<div>{name}</div>
|
||||
</div>
|
||||
<Slider marks={marks}
|
||||
<Slider
|
||||
marks={marks}
|
||||
value={mark}
|
||||
onChange={(val: number) =>
|
||||
setValue((fromLamports(wadToLamports(obligation?.info.borrowAmountWad).toNumber(), repayLiquidityMint) * val / 100).toFixed(2))} />
|
||||
setValue(
|
||||
(
|
||||
(fromLamports(
|
||||
wadToLamports(obligation?.info.borrowAmountWad).toNumber(),
|
||||
repayLiquidityMint
|
||||
) *
|
||||
val) /
|
||||
100
|
||||
).toFixed(2)
|
||||
)
|
||||
}
|
||||
/>
|
||||
<div className="repay-input-title">{LABELS.SELECT_COLLATERAL}</div>
|
||||
<CollateralSelector
|
||||
reserve={repayReserve.info}
|
||||
|
@ -148,9 +170,9 @@ export const RepayInput = (props: {
|
|||
};
|
||||
|
||||
const marks = {
|
||||
0: '0%',
|
||||
25: '25%',
|
||||
50: '50%',
|
||||
75: '75%',
|
||||
100: '100%'
|
||||
0: "0%",
|
||||
25: "25%",
|
||||
50: "50%",
|
||||
75: "75%",
|
||||
100: "100%",
|
||||
};
|
||||
|
|
|
@ -1,9 +1,115 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useMemo, useRef } from "react";
|
||||
import { LendingReserve } from "../../models/lending";
|
||||
import { Card } from "antd";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import "./style.less";
|
||||
import { LABELS } from "../../constants";
|
||||
import echarts from "echarts";
|
||||
import { formatNumber, formatUSD, fromLamports, wadToLamports } from "../../utils/utils";
|
||||
import { useMint } from "../../contexts/accounts";
|
||||
|
||||
export const ReserveUtilizationChart = (props: {
|
||||
reserve: LendingReserve;
|
||||
}) => {
|
||||
const chartDiv = useRef<HTMLDivElement>(null);
|
||||
|
||||
// dispose chart
|
||||
useEffect(() => {
|
||||
const div = chartDiv.current;
|
||||
return () => {
|
||||
let instance = div && echarts.getInstanceByDom(div);
|
||||
instance && instance.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const liquidityMint = useMint(props.reserve.liquidityMint);
|
||||
const avilableLiquidity = fromLamports(
|
||||
props.reserve.totalLiquidity.toNumber(),
|
||||
liquidityMint
|
||||
);
|
||||
|
||||
const totalBorrows = useMemo(
|
||||
() =>
|
||||
fromLamports(wadToLamports(props.reserve.totalBorrowsWad), liquidityMint),
|
||||
[props.reserve, liquidityMint]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartDiv.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
let instance = echarts.getInstanceByDom(chartDiv.current);
|
||||
if (!instance) {
|
||||
instance = echarts.init(chartDiv.current as any);
|
||||
}
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: 'Available Liquidity',
|
||||
value: avilableLiquidity,
|
||||
tokens: avilableLiquidity,
|
||||
},
|
||||
{
|
||||
name: 'Total Borrowed',
|
||||
value: totalBorrows,
|
||||
tokens: totalBorrows,
|
||||
},
|
||||
];
|
||||
|
||||
instance.setOption({
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: function (params: any) {
|
||||
var val = formatUSD.format(params.value);
|
||||
var tokenAmount = formatNumber.format(params.data.tokens);
|
||||
return `${params.name}: \n${val}\n(${tokenAmount})`;
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "Liquidity",
|
||||
type: "pie",
|
||||
radius: ['50%', '70%'],
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
animation: false,
|
||||
label: {
|
||||
fontSize: 14,
|
||||
show: true,
|
||||
formatter: function (params: any) {
|
||||
var val = formatUSD.format(params.value);
|
||||
var tokenAmount = formatNumber.format(params.data.tokens);
|
||||
return `{c|${params.name}}\n{r|${tokenAmount}}\n{r|${val}}`;
|
||||
},
|
||||
rich: {
|
||||
c: {
|
||||
color: "#999",
|
||||
lineHeight: 22,
|
||||
align: "center",
|
||||
},
|
||||
r: {
|
||||
color: "#999",
|
||||
align: "right",
|
||||
},
|
||||
},
|
||||
color: "rgba(255, 255, 255, 0.5)",
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderColor: "#000",
|
||||
},
|
||||
},
|
||||
data,
|
||||
},
|
||||
],
|
||||
});
|
||||
}, [totalBorrows, avilableLiquidity]);
|
||||
|
||||
return <div ref={chartDiv} style={{ height: 300, width: 400 }} />
|
||||
}
|
||||
|
||||
export const ReserveStatus = (props: {
|
||||
className?: string;
|
||||
|
@ -29,7 +135,7 @@ export const ReserveStatus = (props: {
|
|||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
TODO: Reserve Status - add chart
|
||||
<ReserveUtilizationChart reserve={props.reserve} />
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
@ -6,12 +6,10 @@ import {
|
|||
useBorrowedAmount,
|
||||
} from "./../../hooks";
|
||||
import { LendingReserve } from "../../models/lending";
|
||||
import { formatNumber, wadToLamports } from "../../utils/utils";
|
||||
import { formatNumber } from "../../utils/utils";
|
||||
import { Button, Card, Typography } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { cache, ParsedAccount } from "../../contexts/accounts";
|
||||
import { MintInfo } from "@solana/spl-token";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
|
|
|
@ -76,9 +76,7 @@ export const WithdrawInput = (props: {
|
|||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
<div className="withdraw-input-title">
|
||||
{LABELS.WITHDRAW_QUESTION}
|
||||
</div>
|
||||
<div className="withdraw-input-title">{LABELS.WITHDRAW_QUESTION}</div>
|
||||
<div className="token-input">
|
||||
<TokenIcon mintAddress={reserve?.liquidityMint} />
|
||||
<NumericInput
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export * from './ids';
|
||||
export * from './labels';
|
||||
export * from './math';
|
||||
export * from "./ids";
|
||||
export * from "./labels";
|
||||
export * from "./math";
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
export const LABELS = {
|
||||
CONNECT_LABEL: "Connect Wallet",
|
||||
GIVE_SOL: "Give me SOL",
|
||||
FAUCET_INFO: "This faucet will help you fund your accounts outside of Solana main network.",
|
||||
FAUCET_INFO:
|
||||
"This faucet will help you fund your accounts outside of Solana main network.",
|
||||
ACCOUNT_FUNDED: "Account funded.",
|
||||
REPAY_QUESTION: "How much would you like to repay?",
|
||||
REPAY_ACTION: "Repay",
|
||||
RESERVE_STATUS_TITLE: "Reserve Status & Configuration",
|
||||
RESERVE_STATUS_TITLE: "Reserve Status & Configuration",
|
||||
AUDIT_WARNING: "Oyster Lending is unaudited software. Use at your own risk.",
|
||||
MENU_HOME: "Home",
|
||||
MENU_DASHBOARD: "Dashboard",
|
||||
|
@ -27,4 +28,4 @@ export const LABELS = {
|
|||
DASHBOARD_TITLE_DEPOSITS: "Deposts",
|
||||
WITHDRAW_ACTION: "Withdraw",
|
||||
WITHDRAW_QUESTION: "How much would you like to withdraw?",
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useUserAccounts } from "./useUserAccounts";
|
||||
import { useLendingObligations } from "./useLendingObligations";
|
||||
import { TokenAccount } from "../models";
|
||||
import { useEffect, useState } from "react";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { useUserObligationByReserve } from "./useUserObligationByReserve";
|
||||
import { fromLamports, wadToLamports } from "../utils/utils";
|
||||
import { cache, getMultipleAccounts, MintParser, ParsedAccount, useMint } from "../contexts/accounts";
|
||||
import {
|
||||
cache,
|
||||
getMultipleAccounts,
|
||||
MintParser,
|
||||
ParsedAccount,
|
||||
useMint,
|
||||
} from "../contexts/accounts";
|
||||
import { useConnection } from "../contexts/connection";
|
||||
import { MintInfo } from "@solana/spl-token";
|
||||
import { useLendingReserve } from "./useLendingReserves";
|
||||
|
@ -24,30 +27,40 @@ export function useBorrowedAmount(address?: string | PublicKey) {
|
|||
// precache obligation mints
|
||||
const { keys, array } = await getMultipleAccounts(
|
||||
connection,
|
||||
userObligationsByReserve
|
||||
.map(item => item.obligation.info.tokenMint.toBase58()),
|
||||
"single");
|
||||
userObligationsByReserve.map((item) =>
|
||||
item.obligation.info.tokenMint.toBase58()
|
||||
),
|
||||
"single"
|
||||
);
|
||||
|
||||
array.forEach((item, index) => {
|
||||
const address = keys[index];
|
||||
cache.add(new PublicKey(address), item, MintParser);
|
||||
});
|
||||
|
||||
setBorrowedLamports(userObligationsByReserve.reduce((result, item) => {
|
||||
setBorrowedLamports(
|
||||
userObligationsByReserve.reduce((result, item) => {
|
||||
const borrowed = wadToLamports(
|
||||
item.obligation.info.borrowAmountWad
|
||||
).toNumber();
|
||||
|
||||
const borrowed = wadToLamports(item.obligation.info.borrowAmountWad).toNumber();
|
||||
const owned = item.userAccounts.reduce(
|
||||
(amount, acc) => (amount += acc.info.amount.toNumber()),
|
||||
0
|
||||
);
|
||||
const obligationMint = cache.get(
|
||||
item.obligation.info.tokenMint
|
||||
) as ParsedAccount<MintInfo>;
|
||||
|
||||
const owned = item.userAccounts.reduce((amount, acc) => amount += acc.info.amount.toNumber(), 0);
|
||||
const obligationMint = cache.get(item.obligation.info.tokenMint) as ParsedAccount<MintInfo>;
|
||||
|
||||
result += borrowed * owned / obligationMint?.info.supply.toNumber();
|
||||
return result
|
||||
|
||||
}, 0));
|
||||
result += (borrowed * owned) / obligationMint?.info.supply.toNumber();
|
||||
return result;
|
||||
}, 0)
|
||||
);
|
||||
})();
|
||||
}, [connection, userObligationsByReserve]);
|
||||
|
||||
|
||||
}, [userObligationsByReserve]);
|
||||
|
||||
return { borrowed: fromLamports(borrowedLamports, liquidityMint), borrowedLamports };
|
||||
return {
|
||||
borrowed: fromLamports(borrowedLamports, liquidityMint),
|
||||
borrowedLamports,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export function useLendingReserve(address?: string | PublicKey) {
|
|||
>();
|
||||
|
||||
useEffect(() => {
|
||||
setReserveAccount(cache.get(id || ''));
|
||||
setReserveAccount(cache.get(id || ""));
|
||||
|
||||
const dispose = cache.emitter.onCache((args) => {
|
||||
if (args.id === id) {
|
||||
|
|
|
@ -5,14 +5,12 @@ import { PublicKey } from "@solana/web3.js";
|
|||
export function useUserObligationByReserve(reserve?: string | PublicKey) {
|
||||
const { userObligations } = useUserObligations();
|
||||
|
||||
const userObligationsByReserve = useMemo(
|
||||
() => {
|
||||
const id = typeof reserve === 'string' ? reserve : reserve?.toBase58();
|
||||
return userObligations.filter((item) =>
|
||||
item.obligation.info.borrowReserve.toBase58() === id
|
||||
)
|
||||
}, [reserve, userObligations]
|
||||
const userObligationsByReserve = useMemo(() => {
|
||||
const id = typeof reserve === "string" ? reserve : reserve?.toBase58();
|
||||
return userObligations.filter(
|
||||
(item) => item.obligation.info.borrowReserve.toBase58() === id
|
||||
);
|
||||
}, [reserve, userObligations]);
|
||||
|
||||
return {
|
||||
userObligationsByReserve,
|
||||
|
|
|
@ -262,21 +262,26 @@ export const withdrawInstruction = (
|
|||
};
|
||||
|
||||
export const calculateBorrowAPY = (reserve: LendingReserve) => {
|
||||
const totalBorrows = reserve.totalBorrowsWad.div(WAD).toNumber()
|
||||
const currentUtilization = totalBorrows / (reserve.totalLiquidity.toNumber() + totalBorrows)
|
||||
const optimalUtilization = reserve.config.optimalUtilizationRate
|
||||
const totalBorrows = reserve.totalBorrowsWad.div(WAD).toNumber();
|
||||
const currentUtilization =
|
||||
totalBorrows / (reserve.totalLiquidity.toNumber() + totalBorrows);
|
||||
const optimalUtilization = reserve.config.optimalUtilizationRate;
|
||||
let borrowAPY;
|
||||
if (currentUtilization < optimalUtilization) {
|
||||
const normalized_factor = currentUtilization / optimalUtilization;
|
||||
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
|
||||
const minBorrowRate = reserve.config.minBorrowRate / 100;
|
||||
borrowAPY = normalized_factor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
|
||||
borrowAPY =
|
||||
normalized_factor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
|
||||
} else {
|
||||
const normalized_factor = (currentUtilization - optimalUtilization) / (100 - optimalUtilization);
|
||||
const normalized_factor =
|
||||
(currentUtilization - optimalUtilization) / (100 - optimalUtilization);
|
||||
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
|
||||
const maxBorrowRate = reserve.config.maxBorrowRate / 100;
|
||||
borrowAPY = normalized_factor * (maxBorrowRate - optimalBorrowRate) + optimalBorrowRate;
|
||||
borrowAPY =
|
||||
normalized_factor * (maxBorrowRate - optimalBorrowRate) +
|
||||
optimalBorrowRate;
|
||||
}
|
||||
|
||||
return borrowAPY;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
|||
import { LABELS } from "../../constants";
|
||||
import { useUserObligations } from "./../../hooks";
|
||||
import { ObligationItem } from "./obligationItem";
|
||||
import "./style.less"
|
||||
import "./style.less";
|
||||
|
||||
export const DashboardView = () => {
|
||||
const { userObligations } = useUserObligations();
|
||||
|
@ -14,12 +14,14 @@ export const DashboardView = () => {
|
|||
</div>
|
||||
<div>
|
||||
<span>{LABELS.DASHBOARD_TITLE_LOANS}</span>
|
||||
{userObligations.length > 0 && <div className="dashboard-item dashboard-header">
|
||||
{userObligations.length > 0 && (
|
||||
<div className="dashboard-item dashboard-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>}
|
||||
</div>
|
||||
)}
|
||||
{userObligations.map((item) => {
|
||||
return <ObligationItem obligation={item.obligation} />;
|
||||
})}
|
||||
|
|
|
@ -2,11 +2,7 @@ import React from "react";
|
|||
import { useTokenName } from "../../hooks";
|
||||
import { LendingObligation, LendingReserve } from "../../models/lending";
|
||||
import { TokenIcon } from "../../components/TokenIcon";
|
||||
import {
|
||||
wadToLamports,
|
||||
formatNumber,
|
||||
fromLamports,
|
||||
} from "../../utils/utils";
|
||||
import { wadToLamports, formatNumber, fromLamports } from "../../utils/utils";
|
||||
import { Button, Card } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { cache, ParsedAccount, useMint } from "../../contexts/accounts";
|
||||
|
@ -30,9 +26,7 @@ export const ObligationItem = (props: {
|
|||
);
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/repay/loan/${obligation.pubkey.toBase58()}`}
|
||||
>
|
||||
<Link to={`/repay/loan/${obligation.pubkey.toBase58()}`}>
|
||||
<Card>
|
||||
<div className="dashboard-item">
|
||||
<span style={{ display: "flex" }}>
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
import React from "react";
|
||||
import React, { useMemo } from "react";
|
||||
import { useTokenName } from "../../hooks";
|
||||
import { calculateBorrowAPY, LendingReserve } from "../../models/lending";
|
||||
import { TokenIcon } from "../../components/TokenIcon";
|
||||
import { wadToLamports, formatNumber, fromLamports } from "../../utils/utils";
|
||||
import {
|
||||
wadToLamports,
|
||||
formatNumber,
|
||||
fromLamports,
|
||||
formatPct,
|
||||
} from "../../utils/utils";
|
||||
import { Card } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { useMint } from "../../contexts/accounts";
|
||||
import { WAD } from "../../constants";
|
||||
|
||||
export const LendingReserveItem = (props: {
|
||||
reserve: LendingReserve;
|
||||
|
@ -22,10 +26,15 @@ export const LendingReserveItem = (props: {
|
|||
liquidityMint
|
||||
);
|
||||
|
||||
console.log(props.reserve.totalBorrowsWad.toString());
|
||||
const totalBorrows = fromLamports(wadToLamports(props.reserve.totalBorrowsWad), liquidityMint);
|
||||
const totalBorrows = useMemo(
|
||||
() =>
|
||||
fromLamports(wadToLamports(props.reserve.totalBorrowsWad), liquidityMint),
|
||||
[props.reserve, liquidityMint]
|
||||
);
|
||||
|
||||
console.log(liquidityMint);
|
||||
const borrowAPY = useMemo(() => calculateBorrowAPY(props.reserve), [
|
||||
props.reserve,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Link to={`/reserve/${props.address.toBase58()}`}>
|
||||
|
@ -36,18 +45,15 @@ export const LendingReserveItem = (props: {
|
|||
{name}
|
||||
</span>
|
||||
<div>
|
||||
{formatNumber.format(totalLiquidity)} {name}
|
||||
{formatNumber.format(totalLiquidity+totalBorrows)} {name}
|
||||
</div>
|
||||
<div>
|
||||
{formatNumber.format(totalBorrows)} {name}
|
||||
</div>
|
||||
<div>--</div>
|
||||
<div>{calculateBorrowAPY(props.reserve)}</div>
|
||||
<div>{formatPct.format(borrowAPY)}</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,9 @@ export const RepayReserveView = () => {
|
|||
}>();
|
||||
|
||||
const lendingObligation = useLendingObligation(obligationId);
|
||||
const lendingReserve = useLendingReserve(obligationId ? lendingObligation?.info.borrowReserve : reserveId);
|
||||
const lendingReserve = useLendingReserve(
|
||||
obligationId ? lendingObligation?.info.borrowReserve : reserveId
|
||||
);
|
||||
const reserve = lendingReserve?.info;
|
||||
|
||||
console.log([reserveId, obligationId]);
|
||||
|
|
Loading…
Reference in New Issue