From 3c3ba90ffcbae89619ca894cadc8d3435738972a Mon Sep 17 00:00:00 2001 From: bartosz-lipinski <264380+bartosz-lipinski@users.noreply.github.com> Date: Thu, 26 Nov 2020 01:18:18 -0600 Subject: [PATCH] feat: add APR/APY and utilization --- src/components/SideReserveOverview/index.tsx | 18 +++++++++--------- src/constants/labels.ts | 1 + src/models/lending/borrow.ts | 10 +++++----- src/models/lending/deposit.ts | 4 ++-- src/models/lending/reserve.ts | 6 ++++++ src/views/borrow/item.tsx | 11 +++++++---- src/views/deposit/view/item.tsx | 11 +++++++---- src/views/home/item.tsx | 4 ++-- 8 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/components/SideReserveOverview/index.tsx b/src/components/SideReserveOverview/index.tsx index db5d4f4..b43765e 100644 --- a/src/components/SideReserveOverview/index.tsx +++ b/src/components/SideReserveOverview/index.tsx @@ -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: { <>
- Deposit APY: + {LABELS.TABLE_TITLE_DEPOSIT_APR}:
{formatPct.format(depositApy)}
@@ -80,9 +80,9 @@ export const SideReserveOverview = (props: { <>
- Borrow APY: + {LABELS.TABLE_TITLE_BORROW_APR}: -
{formatPct.format(borrowApy)}
+
{formatPct.format(borrowApr)}
); diff --git a/src/constants/labels.ts b/src/constants/labels.ts index f4e0940..098d192 100644 --- a/src/constants/labels.ts +++ b/src/constants/labels.ts @@ -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", }; diff --git a/src/models/lending/borrow.ts b/src/models/lending/borrow.ts index 1e67a12..a4ded96 100644 --- a/src/models/lending/borrow.ts +++ b/src/models/lending/borrow.ts @@ -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; }; diff --git a/src/models/lending/deposit.ts b/src/models/lending/deposit.ts index 06a8912..4e74bb1 100644 --- a/src/models/lending/deposit.ts +++ b/src/models/lending/deposit.ts @@ -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; }; diff --git a/src/models/lending/reserve.ts b/src/models/lending/reserve.ts index 2e39bcb..878732e 100644 --- a/src/models/lending/reserve.ts +++ b/src/models/lending/reserve.ts @@ -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()); +} \ No newline at end of file diff --git a/src/views/borrow/item.tsx b/src/views/borrow/item.tsx index 7fd43ea..c9b83d7 100644 --- a/src/views/borrow/item.tsx +++ b/src/views/borrow/item.tsx @@ -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 ( @@ -27,10 +30,10 @@ export const BorrowItem = (props: {
{formatNumber.format(collateralBalance)} {name}
-
--
+
{formatPct.format(apr)}
diff --git a/src/views/deposit/view/item.tsx b/src/views/deposit/view/item.tsx index b1bc3d2..a90b880 100644 --- a/src/views/deposit/view/item.tsx +++ b/src/views/deposit/view/item.tsx @@ -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 ( @@ -33,10 +36,10 @@ export const ReserveItem = (props: {
{formatNumber.format(collateralBalance)} {name}
-
--
+
{formatPct.format(apy)}
diff --git a/src/views/home/item.tsx b/src/views/home/item.tsx index 2b81d2d..c2d8ecc 100644 --- a/src/views/home/item.tsx +++ b/src/views/home/item.tsx @@ -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, ]);