feat: add APR/APY and utilization
This commit is contained in:
parent
6bd3967c36
commit
3c3ba90ffc
|
@ -1,11 +1,12 @@
|
|||
import React from "react";
|
||||
import { useTokenName } from "./../../hooks";
|
||||
import { LendingReserve } from "../../models/lending";
|
||||
import { calculateBorrowAPR, calculateDepositAPY, calculateUtilizationRatio, LendingReserve } from "../../models/lending";
|
||||
import { TokenIcon } from "../../components/TokenIcon";
|
||||
import { formatNumber, formatPct, fromLamports } from "../../utils/utils";
|
||||
import { formatNumber, formatPct, fromLamports, wadToLamports } from "../../utils/utils";
|
||||
import { Card, Typography } from "antd";
|
||||
import { ParsedAccount, useMint } from "../../contexts/accounts";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LABELS } from "../../constants";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
|
@ -29,11 +30,10 @@ export const SideReserveOverview = (props: {
|
|||
liquidityMint
|
||||
);
|
||||
|
||||
// TODO: calculate
|
||||
const depositApy = 0.048;
|
||||
const borrowApy = 0.048;
|
||||
const depositApy = calculateDepositAPY(reserve);
|
||||
const borrowApr = calculateBorrowAPR(reserve);
|
||||
|
||||
const utilizationRate = reserve.config.loanToValueRatio / 100;
|
||||
const utilizationRate = calculateUtilizationRatio(reserve);
|
||||
const liquidiationThreshold = reserve.config.optimalUtilizationRate / 100;
|
||||
const liquidiationPenalty = reserve.config.liquidationBonus / 100;
|
||||
const maxLTV = liquidiationThreshold - liquidiationPenalty;
|
||||
|
@ -44,7 +44,7 @@ export const SideReserveOverview = (props: {
|
|||
<>
|
||||
<div className="card-row">
|
||||
<Text type="secondary" className="card-cell ">
|
||||
Deposit APY:
|
||||
{LABELS.TABLE_TITLE_DEPOSIT_APR}:
|
||||
</Text>
|
||||
<div className="card-cell ">{formatPct.format(depositApy)}</div>
|
||||
</div>
|
||||
|
@ -80,9 +80,9 @@ export const SideReserveOverview = (props: {
|
|||
<>
|
||||
<div className="card-row">
|
||||
<Text type="secondary" className="card-cell ">
|
||||
Borrow APY:
|
||||
{LABELS.TABLE_TITLE_BORROW_APR}:
|
||||
</Text>
|
||||
<div className="card-cell ">{formatPct.format(borrowApy)}</div>
|
||||
<div className="card-cell ">{formatPct.format(borrowApr)}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -38,4 +38,5 @@ export const LABELS = {
|
|||
WITHDRAW_QUESTION: "How much would you like to withdraw?",
|
||||
DASHBOARD_ACTION: "Go to dashboard",
|
||||
GO_BACK_ACTION: "Go back",
|
||||
DEPOSIT_ACTION: "Deposit",
|
||||
};
|
||||
|
|
|
@ -111,27 +111,27 @@ export const borrowInstruction = (
|
|||
|
||||
// deposit APY utilization currentUtilizationRate * borrowAPY
|
||||
|
||||
export const calculateBorrowAPY = (reserve: LendingReserve) => {
|
||||
export const calculateBorrowAPR = (reserve: LendingReserve) => {
|
||||
const totalBorrows = reserve.borrowedLiquidityWad.div(WAD).toNumber();
|
||||
const currentUtilization =
|
||||
totalBorrows / (reserve.availableLiqudity.toNumber() + totalBorrows);
|
||||
const optimalUtilization = reserve.config.optimalUtilizationRate;
|
||||
let borrowAPY;
|
||||
let borrowAPR;
|
||||
if (currentUtilization < optimalUtilization) {
|
||||
const normalized_factor = currentUtilization / optimalUtilization;
|
||||
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
|
||||
const minBorrowRate = reserve.config.minBorrowRate / 100;
|
||||
borrowAPY =
|
||||
borrowAPR =
|
||||
normalized_factor * (optimalBorrowRate - minBorrowRate) + minBorrowRate;
|
||||
} else {
|
||||
const normalized_factor =
|
||||
(currentUtilization - optimalUtilization) / (100 - optimalUtilization);
|
||||
const optimalBorrowRate = reserve.config.optimalBorrowRate / 100;
|
||||
const maxBorrowRate = reserve.config.maxBorrowRate / 100;
|
||||
borrowAPY =
|
||||
borrowAPR =
|
||||
normalized_factor * (maxBorrowRate - optimalBorrowRate) +
|
||||
optimalBorrowRate;
|
||||
}
|
||||
|
||||
return borrowAPY;
|
||||
return borrowAPR;
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as BufferLayout from "buffer-layout";
|
|||
import { WAD } from "../../constants";
|
||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
||||
import * as Layout from "./../../utils/layout";
|
||||
import { calculateBorrowAPY } from "./borrow";
|
||||
import { calculateBorrowAPR } from "./borrow";
|
||||
import { LendingInstruction } from "./lending";
|
||||
import { LendingReserve } from "./reserve";
|
||||
|
||||
|
@ -68,6 +68,6 @@ export const calculateDepositAPY = (reserve: LendingReserve) => {
|
|||
const currentUtilization =
|
||||
totalBorrows / (reserve.availableLiqudity.toNumber() + totalBorrows);
|
||||
|
||||
const borrowAPY = calculateBorrowAPY(reserve);
|
||||
const borrowAPY = calculateBorrowAPR(reserve);
|
||||
return currentUtilization * borrowAPY;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import BN from "bn.js";
|
||||
import * as BufferLayout from "buffer-layout";
|
||||
import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../../constants/ids";
|
||||
import { wadToLamports } from "../../utils/utils";
|
||||
import * as Layout from "./../../utils/layout";
|
||||
import { LendingInstruction } from "./lending";
|
||||
|
||||
|
@ -168,3 +169,8 @@ export const initReserveInstruction = (
|
|||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const calculateUtilizationRatio = (reserve: LendingReserve) => {
|
||||
return reserve.availableLiqudity.toNumber() /
|
||||
(reserve.availableLiqudity.toNumber() + wadToLamports(reserve.borrowedLiquidityWad).toNumber());
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
import React from "react";
|
||||
import { useCollateralBalance, useTokenName } from "../../hooks";
|
||||
import { LendingReserve } from "../../models/lending";
|
||||
import { calculateBorrowAPR, LendingReserve } from "../../models/lending";
|
||||
import { TokenIcon } from "../../components/TokenIcon";
|
||||
import { formatNumber } from "../../utils/utils";
|
||||
import { formatNumber, formatPct } from "../../utils/utils";
|
||||
import { Button, Card } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { LABELS } from "../../constants";
|
||||
|
||||
export const BorrowItem = (props: {
|
||||
reserve: LendingReserve;
|
||||
|
@ -16,6 +17,8 @@ export const BorrowItem = (props: {
|
|||
// TODO: calculate avilable amount... based on total owned collateral across all the reserves
|
||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||
|
||||
const apr = calculateBorrowAPR(props.reserve);
|
||||
|
||||
return (
|
||||
<Link to={`/borrow/${props.address.toBase58()}`}>
|
||||
<Card>
|
||||
|
@ -27,10 +30,10 @@ export const BorrowItem = (props: {
|
|||
<div>
|
||||
{formatNumber.format(collateralBalance)} {name}
|
||||
</div>
|
||||
<div>--</div>
|
||||
<div>{formatPct.format(apr)}</div>
|
||||
<div>
|
||||
<Button>
|
||||
<span>Borrow</span>
|
||||
<span>{LABELS.BORROW_ACTION}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,12 +4,13 @@ import {
|
|||
useTokenName,
|
||||
useUserBalance,
|
||||
} from "../../../hooks";
|
||||
import { LendingReserve } from "../../../models/lending";
|
||||
import { calculateDepositAPY, LendingReserve } from "../../../models/lending";
|
||||
import { TokenIcon } from "../../../components/TokenIcon";
|
||||
import { formatNumber } from "../../../utils/utils";
|
||||
import { formatNumber, formatPct } from "../../../utils/utils";
|
||||
import { Button, Card } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { LABELS } from "../../../constants";
|
||||
|
||||
export const ReserveItem = (props: {
|
||||
reserve: LendingReserve;
|
||||
|
@ -19,6 +20,8 @@ export const ReserveItem = (props: {
|
|||
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
|
||||
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
|
||||
|
||||
const apy = calculateDepositAPY(props.reserve);
|
||||
|
||||
return (
|
||||
<Link to={`/deposit/${props.address.toBase58()}`}>
|
||||
<Card>
|
||||
|
@ -33,10 +36,10 @@ export const ReserveItem = (props: {
|
|||
<div>
|
||||
{formatNumber.format(collateralBalance)} {name}
|
||||
</div>
|
||||
<div>--</div>
|
||||
<div>{formatPct.format(apy)}</div>
|
||||
<div>
|
||||
<Button>
|
||||
<span>Deposit</span>
|
||||
<span>{LABELS.DEPOSIT_ACTION}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo } from "react";
|
||||
import { useTokenName } from "../../hooks";
|
||||
import {
|
||||
calculateBorrowAPY,
|
||||
calculateBorrowAPR,
|
||||
calculateDepositAPY,
|
||||
LendingReserve,
|
||||
} from "../../models/lending";
|
||||
|
@ -39,7 +39,7 @@ export const LendingReserveItem = (props: {
|
|||
[props.reserve, liquidityMint]
|
||||
);
|
||||
|
||||
const borrowAPY = useMemo(() => calculateBorrowAPY(props.reserve), [
|
||||
const borrowAPY = useMemo(() => calculateBorrowAPR(props.reserve), [
|
||||
props.reserve,
|
||||
]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue