feat: add APR/APY and utilization

This commit is contained in:
bartosz-lipinski 2020-11-26 01:18:18 -06:00
parent 6bd3967c36
commit 3c3ba90ffc
8 changed files with 39 additions and 26 deletions

View File

@ -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>
</>
);

View File

@ -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",
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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());
}

View File

@ -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>

View File

@ -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>

View File

@ -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,
]);