feat: repay

This commit is contained in:
bartosz-lipinski 2020-11-24 14:05:38 -06:00
parent 8bdcdab94f
commit 31020e7e86
30 changed files with 287 additions and 81 deletions

View File

@ -19,4 +19,5 @@ Any content produced by Solana, or developer resources that Solana provides, are
- [] Add slider to borrow page (100% max collateral)
- [] Add market size on front page
- [] Add github link
- [] Repay from reserve (add selection for obligation/loan)
- []

View File

@ -13,7 +13,7 @@ import { LENDING_PROGRAM_ID, TOKEN_PROGRAM_ID } from "../constants/ids";
import { findOrCreateAccountByMint } from "./account";
import { LendingObligation, TokenAccount } from "../models";
import { ParsedAccount } from "../contexts/accounts";
import { decimalToLamports } from "../utils/utils";
import { wadToLamports } from "../utils/utils";
export const repay = async (
from: TokenAccount, // CollateralAccount
@ -76,7 +76,7 @@ export const repay = async (
signers
);
const loanRatio = amountLamports / decimalToLamports(obligation.info.borrowAmount)
const loanRatio = amountLamports / wadToLamports(obligation.info.borrowAmountWad)
.toNumber();
console.log(loanRatio);

View File

@ -4,6 +4,7 @@ import { useWallet } from "../../contexts/wallet";
import { CurrentUserBadge } from "../CurrentUserBadge";
import { SettingOutlined } from "@ant-design/icons";
import { Settings } from "../Settings";
import { LABELS } from "../../constants";
export const AppBar = (props: { left?: JSX.Element; right?: JSX.Element }) => {
const { connected, wallet } = useWallet();
@ -19,20 +20,20 @@ export const AppBar = (props: { left?: JSX.Element; right?: JSX.Element }) => {
onClick={connected ? wallet.disconnect : wallet.connect}
style={{ color: "#2abdd2" }}
>
Connect
{LABELS.CONNECT_BUTTON}
</Button>
)}
{connected && (
<Popover
placement="bottomRight"
title="Wallet public key"
title={LABELS.WALLET_TOOLTIP}
trigger="click"
></Popover>
)}
</div>
<Popover
placement="topRight"
title="Settings"
title={LABELS.SETTINGS_TOOLTIP}
content={<Settings />}
trigger="click"
>

View File

@ -11,6 +11,7 @@ import { borrow } from "../../actions";
import { PublicKey } from "@solana/web3.js";
import { CollateralSelector } from "./../CollateralSelector";
import "./style.less";
import { LABELS } from "../../constants";
export const BorrowInput = (props: {
className?: string;
@ -84,7 +85,7 @@ export const BorrowInput = (props: {
}}
>
<div className="borrow-input-title">
How much would you like to borrow?
{LABELS.BORROW_QUESTION}
</div>
<div className="token-input">
<TokenIcon mintAddress={borrowReserve?.liquidityMint} />
@ -104,7 +105,7 @@ export const BorrowInput = (props: {
/>
<div>{name}</div>
</div>
<div className="borrow-input-title">Select collateral account?</div>
<div className="borrow-input-title">{LABELS.SELECT_COLLATERAL}</div>
<CollateralSelector
reserve={borrowReserve}
mint={collateralReserveMint}
@ -116,7 +117,7 @@ export const BorrowInput = (props: {
onClick={onBorrow}
disabled={fromAccounts.length === 0}
>
Borrow
{LABELS.BORROW_ACTION}
</Button>
</div>
</Card>

View File

@ -0,0 +1,13 @@
import { Button } from "antd"
import { ButtonProps } from "antd/lib/button"
import React from "react"
import { useWallet } from "../../contexts/wallet";
import { LABELS } from './../../constants';
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} >
{connected ? props.children : LABELS.CONNECT_LABEL}
</Button>
}

View File

@ -14,6 +14,7 @@ import BasicLayout from "@ant-design/pro-layout";
import { AppBar } from "./../AppBar";
import { Link, useLocation } from "react-router-dom";
import { useConnectionConfig } from "../../contexts/connection";
import { LABELS } from "../../constants";
export const AppLayout = (props: any) => {
const { env } = useConnectionConfig();
@ -36,11 +37,11 @@ export const AppLayout = (props: any) => {
<div className="App">
<div className="Banner">
<div className="Banner-description">
Oyster Lending is unaudited software. Use at your own risk.
{LABELS.AUDIT_WARNING}
</div>
</div>
<BasicLayout
title="Oyster Lending"
title={LABELS.APP_TITLE}
navTheme="realDark"
headerTheme="dark"
theme="dark"
@ -62,7 +63,7 @@ export const AppLayout = (props: any) => {
pathname: "/",
}}
>
Home
{LABELS.MENU_HOME}
</Link>
</Menu.Item>
<Menu.Item key="2" icon={<PieChartOutlined />}>
@ -71,7 +72,7 @@ export const AppLayout = (props: any) => {
pathname: "/dashboard",
}}
>
Dashboard
{LABELS.MENU_DASHBOARD}
</Link>
</Menu.Item>
<Menu.Item key="3" icon={<BankOutlined />}>
@ -80,7 +81,7 @@ export const AppLayout = (props: any) => {
pathname: "/deposit",
}}
>
Deposit
{LABELS.MENU_DEPOSIT}
</Link>
</Menu.Item>
<Menu.Item key="4" icon={<LogoutOutlined />}>
@ -89,7 +90,7 @@ export const AppLayout = (props: any) => {
pathname: "/borrow",
}}
>
Borrow
{LABELS.MENU_BORROW}
</Link>
</Menu.Item>
{env !== "mainnet-beta" && (
@ -99,7 +100,7 @@ export const AppLayout = (props: any) => {
pathname: "/faucet",
}}
>
Faucet
{LABELS.MENU_FAUCET}
</Link>
</Menu.Item>
)}

View File

@ -14,7 +14,8 @@ import { useWallet } from "../../contexts/wallet";
import { repay } from "../../actions";
import { CollateralSelector } from "./../CollateralSelector";
import "./style.less";
import { decimalToLamports, formatNumber, fromLamports, toLamports } from "../../utils/utils";
import { wadToLamports, formatNumber, fromLamports, toLamports } from "../../utils/utils";
import { LABELS } from "../../constants";
export const RepayInput = (props: {
className?: string;
@ -51,9 +52,9 @@ export const RepayInput = (props: {
const lamports = useMemo(() => toLamports(parseFloat(value), repayLiquidityMint), [value, repayLiquidityMint]);
const mark = decimalToLamports(obligation?.info.borrowAmount).toNumber() / lamports * 100;
const mark = wadToLamports(obligation?.info.borrowAmountWad).toNumber() / lamports * 100;
const onReoay = useCallback(() => {
const onRepay = useCallback(() => {
if (
!collateralReserve ||
!obligation ||
@ -102,7 +103,7 @@ export const RepayInput = (props: {
}}
>
<div className="repay-input-title">
How much would you like to repay? (Currently:{" "}
{LABELS.REPAY_QUESTION} (Currently:{" "})
{formatNumber.format(balance)} {name})
</div>
<div className="token-input">
@ -126,8 +127,8 @@ export const RepayInput = (props: {
<Slider marks={marks}
value={mark}
onChange={(val: number) =>
setValue((fromLamports(decimalToLamports(obligation?.info.borrowAmount).toNumber(), repayLiquidityMint) * val / 100).toFixed(2))} />
<div className="repay-input-title">Select collateral account?</div>
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}
mint={collateralReserveMint}
@ -136,10 +137,10 @@ export const RepayInput = (props: {
<Button
type="primary"
onClick={onReoay}
onClick={onRepay}
disabled={fromAccounts.length === 0}
>
Repay
{LABELS.REPAY_ACTION}
</Button>
</div>
</Card>

View File

@ -3,6 +3,7 @@ import { LendingReserve } from "../../models/lending";
import { Card } from "antd";
import { PublicKey } from "@solana/web3.js";
import "./style.less";
import { LABELS } from "../../constants";
export const ReserveStatus = (props: {
className?: string;
@ -18,7 +19,7 @@ export const ReserveStatus = (props: {
return (
<Card
className={props.className}
title={<>Reserve Status &amp; Configuration</>}
title={<>{LABELS.RESERVE_STATUS_TITLE}</>}
bodyStyle={bodyStyle}
>
<div

View File

@ -35,7 +35,7 @@ export const SideReserveOverview = (props: {
const borrowApy = 0.048;
const utilizationRate = reserve.config.loanToValueRatio / 100;
const liquidiationThreshold = reserve.config.maxUtilizationRate / 100;
const liquidiationThreshold = reserve.config.optimalUtilizationRate / 100;
const liquidiationPenalty = reserve.config.liquidationBonus / 100;
const maxLTV = liquidiationThreshold - liquidiationPenalty;

View File

@ -3,12 +3,15 @@ import {
useCollateralBalance,
useTokenName,
useUserBalance,
useBorrowedAmount,
} from "./../../hooks";
import { LendingReserve } from "../../models/lending";
import { formatNumber } from "../../utils/utils";
import { formatNumber, wadToLamports } 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;
@ -25,8 +28,9 @@ export const UserLendingCard = (props: {
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
const { borrowed: totalBorrowed } = useBorrowedAmount(address);
// TODO: calculate
const borrowed = 0;
const healthFactor = "--";
const ltv = 0;
const available = 0;
@ -54,7 +58,7 @@ export const UserLendingCard = (props: {
Borrowed
</Text>
<div className="card-cell ">
{formatNumber.format(borrowed)} {name}
{formatNumber.format(totalBorrowed)} {name}
</div>
</div>

View File

@ -13,6 +13,7 @@ import { useWallet } from "../../contexts/wallet";
import { withdraw } from "../../actions";
import { PublicKey } from "@solana/web3.js";
import "./style.less";
import { LABELS } from "../../constants";
export const WithdrawInput = (props: {
className?: string;
@ -76,7 +77,7 @@ export const WithdrawInput = (props: {
}}
>
<div className="withdraw-input-title">
How much would you like to withdraw?
{LABELS.WITHDRAW_QUESTION}
</div>
<div className="token-input">
<TokenIcon mintAddress={reserve?.liquidityMint} />
@ -102,7 +103,7 @@ export const WithdrawInput = (props: {
onClick={onWithdraw}
disabled={fromAccounts.length === 0}
>
Withdraw
{LABELS.WITHDRAW_ACTION}
</Button>
</div>
</Card>

3
src/constants/index.tsx Normal file
View File

@ -0,0 +1,3 @@
export * from './ids';
export * from './labels';
export * from './math';

30
src/constants/labels.ts Normal file
View File

@ -0,0 +1,30 @@
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.",
ACCOUNT_FUNDED: "Account funded.",
REPAY_QUESTION: "How much would you like to repay?",
REPAY_ACTION: "Repay",
RESERVE_STATUS_TITLE: "Reserve Status &amp; Configuration",
AUDIT_WARNING: "Oyster Lending is unaudited software. Use at your own risk.",
MENU_HOME: "Home",
MENU_DASHBOARD: "Dashboard",
MENU_DEPOSIT: "Deposit",
MENU_BORROW: "Borrow",
MENU_FAUCET: "Faucet",
APP_TITLE: "Oyster Lending",
CONNECT_BUTTON: "Connect",
WALLET_TOOLTIP: "Wallet public key",
SETTINGS_TOOLTIP: "Settings",
SELECT_COLLATERAL: "Select collateral account?",
BORROW_QUESTION: "How much would you like to borrow?",
BORROW_ACTION: "Borrow",
TABLE_TITLE_ASSET: "Asset",
TABLE_TITLE_LOAN_BALANCE: "Your loan balan",
TABLE_TITLE_APY: "APY",
TABLE_TITLE_ACTION: "Action",
DASHBOARD_TITLE_LOANS: "Loans",
DASHBOARD_TITLE_DEPOSITS: "Deposts",
WITHDRAW_ACTION: "Withdraw",
WITHDRAW_QUESTION: "How much would you like to withdraw?",
}

6
src/constants/math.ts Normal file
View File

@ -0,0 +1,6 @@
import BN from "bn.js";
export const TEN = new BN(10);
export const WAD = TEN.pow(new BN(18));
export const RAY = TEN.pow(new BN(27));
export const ZERO = new BN(0);

View File

@ -7,3 +7,4 @@ export * from "./useCollateralBalance";
export * from "./useLendingObligations";
export * from "./useUserObligations";
export * from "./useUserObligationByReserve";
export * from "./useBorrowedAmount";

View File

@ -0,0 +1,53 @@
import { useEffect, useMemo, useState } from "react";
import { useUserAccounts } from "./useUserAccounts";
import { useLendingObligations } from "./useLendingObligations";
import { TokenAccount } from "../models";
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 { useConnection } from "../contexts/connection";
import { MintInfo } from "@solana/spl-token";
import { useLendingReserve } from "./useLendingReserves";
export function useBorrowedAmount(address?: string | PublicKey) {
const connection = useConnection();
const { userObligationsByReserve } = useUserObligationByReserve(address);
const [borrowedLamports, setBorrowedLamports] = useState(0);
const reserve = useLendingReserve(address);
const liquidityMint = useMint(reserve?.info.liquidityMint);
useEffect(() => {
setBorrowedLamports(0);
(async () => {
// precache obligation mints
const { keys, array } = await getMultipleAccounts(
connection,
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) => {
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>;
result += borrowed * owned / obligationMint?.info.supply.toNumber();
return result
}, 0));
})();
}, [userObligationsByReserve]);
return { borrowed: fromLamports(borrowedLamports, liquidityMint), borrowedLamports };
}

View File

@ -34,14 +34,14 @@ export function useLendingReserves() {
};
}
export function useLendingReserve(address: string | PublicKey) {
export function useLendingReserve(address?: string | PublicKey) {
const id = typeof address === "string" ? address : address?.toBase58();
const [reserveAccount, setReserveAccount] = useState<
ParsedAccount<LendingReserve>
>();
useEffect(() => {
setReserveAccount(cache.get(id));
setReserveAccount(cache.get(id || ''));
const dispose = cache.emitter.onCache((args) => {
if (args.id === id) {

View File

@ -2,15 +2,16 @@ import { useMemo } from "react";
import { useUserObligations } from "./useUserObligations";
import { PublicKey } from "@solana/web3.js";
export function useUserObligationByReserve(reserve: PublicKey) {
export function useUserObligationByReserve(reserve?: string | PublicKey) {
const { userObligations } = useUserObligations();
const userObligationsByReserve = useMemo(
() =>
userObligations.filter((item) =>
item.oblication.info.borrowReserve.equals(reserve)
),
[reserve, userObligations]
() => {
const id = typeof reserve === 'string' ? reserve : reserve?.toBase58();
return userObligations.filter((item) =>
item.obligation.info.borrowReserve.toBase58() === id
)
}, [reserve, userObligations]
);
return {

View File

@ -26,7 +26,7 @@ export function useUserObligations() {
)
.map((ob) => {
return {
oblication: ob,
obligation: ob,
userAccounts: [...accountsByMint.get(ob.info.tokenMint.toBase58())],
// TODO: add total borrowed amount?

View File

@ -12,9 +12,9 @@ export const LendingObligationLayout: typeof BufferLayout.Structure = BufferLayo
/// Reserve which collateral tokens were deposited into
Layout.publicKey("collateralSupply"),
/// Borrow rate used for calculating interest.
Layout.uint128("cumulativeBorrowRate"),
Layout.uint128("cumulativeBorrowRateWad"),
/// Amount of tokens borrowed for this obligation plus interest
Layout.uint128("borrowAmount"),
Layout.uint128("borrowAmountWad"),
/// Reserve which tokens were borrowed from
Layout.publicKey("borrowReserve"),
/// Mint address of the tokens for this obligation
@ -30,8 +30,8 @@ export interface LendingObligation {
lastUpdateSlot: BN;
collateralAmount: BN;
collateralSupply: PublicKey;
cumulativeBorrowRate: BN; // decimals
borrowAmount: BN; // decimals
cumulativeBorrowRateWad: BN; // decimals
borrowAmountWad: BN; // decimals
borrowReserve: PublicKey;
tokenMint: PublicKey;
}

View File

@ -7,6 +7,7 @@ import {
} from "@solana/web3.js";
import BN from "bn.js";
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 { LendingInstruction } from "./lending";
@ -26,20 +27,26 @@ export const LendingReserveLayout: typeof BufferLayout.Structure = BufferLayout.
BufferLayout.struct(
[
/// Max utilization rate as a percent
BufferLayout.u8("maxUtilizationRate"),
/// Optimal utilization rate as a percent
BufferLayout.u8("optimalUtilizationRate"),
/// The ratio of the loan to the value of the collateral as a percent
BufferLayout.u8("loanToValueRatio"),
/// The percent discount the liquidator gets when buying collateral for an unhealthy obligation
BufferLayout.u8("liquidationBonus"),
/// The percent at which an obligation is considered unhealthy
BufferLayout.u8("liquidationThreshold"),
/// Min borrow APY
BufferLayout.u8("minBorrowRate"),
/// Optimal (utilization) borrow APY
BufferLayout.u8("optimalBorrowRate"),
/// Max borrow APY
BufferLayout.u8("maxBorrowRate"),
],
"config"
),
Layout.uint128("cumulativeBorrowRate"),
Layout.uint128("totalBorrows"),
Layout.uint128("cumulativeBorrowRateWad"),
Layout.uint128("totalBorrowsWad"),
Layout.uint64("totalLiquidity"),
Layout.uint64("collateralMintSupply"),
@ -66,15 +73,18 @@ export interface LendingReserve {
dexMarketPrice: BN; // what is precision on the price?
config: {
maxUtilizationRate: number;
optimalUtilizationRate: number;
loanToValueRatio: number;
liquidationBonus: number;
liquidationThreshold: number;
minBorrowRate: number;
optimalBorrowRate: number;
maxBorrowRate: number;
};
// collateralFactor: number;
cumulativeBorrowRate: BN;
totalBorrows: BN;
cumulativeBorrowRateWad: BN;
totalBorrowsWad: BN;
totalLiquidity: BN;
collateralMintSupply: BN;
@ -250,3 +260,23 @@ export const withdrawInstruction = (
data,
});
};
export const calculateBorrowAPY = (reserve: LendingReserve) => {
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;
} else {
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;
}
return borrowAPY;
}

View File

@ -54,7 +54,7 @@ export function Routes() {
children={<BorrowReserveView />}
/>
<Route
path="/repay/:reserve/:obligation"
path="/repay/loan/:obligation"
children={<RepayReserveView />}
/>
<Route

View File

@ -4,6 +4,7 @@ import { MintInfo } from "@solana/spl-token";
import { TokenAccount } from "./../models";
import { PublicKey } from "@solana/web3.js";
import BN from "bn.js";
import { WAD, ZERO } from "../constants";
export interface KnownToken {
tokenSymbol: string;
@ -106,9 +107,8 @@ export function toLamports(
return amount * precision;
}
export function decimalToLamports(amount?: BN): BN {
// TODO: check math
return amount?.div(new BN(10).pow(new BN(18))) || new BN(0);
export function wadToLamports(amount?: BN): BN {
return amount?.div(WAD) || ZERO;
}
export function fromLamports(

View File

@ -0,0 +1,46 @@
import React from "react";
import {
useCollateralBalance,
useTokenName,
useUserBalance,
} from "../../hooks";
import { LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { formatNumber } from "../../utils/utils";
import { Button, Card } from "antd";
import { Link } from "react-router-dom";
import { PublicKey } from "@solana/web3.js";
export const ReserveItem = (props: {
reserve: LendingReserve;
address: PublicKey;
}) => {
const name = useTokenName(props.reserve.liquidityMint);
const { balance: tokenBalance } = useUserBalance(props.reserve.liquidityMint);
const { balance: collateralBalance } = useCollateralBalance(props.reserve);
return (
<Link to={`/deposit/${props.address.toBase58()}`}>
<Card>
<div className="deposit-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={props.reserve.liquidityMint} />
{name}
</span>
<div>
{formatNumber.format(tokenBalance)} {name}
</div>
<div>
{formatNumber.format(collateralBalance)} {name}
</div>
<div>--</div>
<div>
<Button>
<span>Deposit</span>
</Button>
</div>
</div>
</Card>
</Link>
);
};

View File

@ -1,22 +1,27 @@
import React from "react";
import { LABELS } from "../../constants";
import { useUserObligations } from "./../../hooks";
import { ObligationItem } from "./obligationItem";
import "./style.less"
export const DashboardView = () => {
const { userObligations } = useUserObligations();
return (
<div className="flexColumn">
<div className="dashboard-container">
<div>
<span>Loans</span>
{userObligations.length > 0 && <div className="deposit-item deposit-header">
<div>Asset</div>
<div>Your loan balance</div>
<div>APY</div>
<div>Action</div>
<span>{LABELS.DASHBOARD_TITLE_DEPOSITS}</span>
</div>
<div>
<span>{LABELS.DASHBOARD_TITLE_LOANS}</span>
{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>}
{userObligations.map((item) => {
return <ObligationItem obligation={item.oblication} />;
return <ObligationItem obligation={item.obligation} />;
})}
</div>
</div>

View File

@ -3,7 +3,7 @@ import { useTokenName } from "../../hooks";
import { LendingObligation, LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import {
decimalToLamports,
wadToLamports,
formatNumber,
fromLamports,
} from "../../utils/utils";
@ -25,16 +25,16 @@ export const ObligationItem = (props: {
const liquidityMint = useMint(borrowReserve.info.liquidityMint);
const borrowAmount = fromLamports(
decimalToLamports(obligation.info.borrowAmount),
wadToLamports(obligation.info.borrowAmountWad),
liquidityMint
);
return (
<Link
to={`/repay/${borrowReserve?.pubkey.toBase58()}/${obligation.pubkey.toBase58()}`}
to={`/repay/loan/${obligation.pubkey.toBase58()}`}
>
<Card>
<div className="borrow-item">
<div className="dashboard-item">
<span style={{ display: "flex" }}>
<TokenIcon mintAddress={borrowReserve?.info.liquidityMint} />
{name}

View File

@ -1,4 +1,4 @@
.borrow-item {
.dashboard-item {
display: flex;
justify-content: space-between;
align-items: center;
@ -14,7 +14,7 @@
}
}
.borrow-header {
.dashboard-header {
margin: 0px 30px;
& > div {

View File

@ -1,9 +1,11 @@
import React, { useCallback } from "react";
import { Button, Card } from "antd";
import { Card } from "antd";
import { useConnection } from "../../contexts/connection";
import { useWallet } from "../../contexts/wallet";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
import { notify } from "../../utils/notifications";
import { ConnectButton } from "./../../components/ConnectButton";
import { LABELS } from "../../constants";
export const FaucetView = () => {
const connection = useConnection();
@ -14,7 +16,7 @@ export const FaucetView = () => {
.requestAirdrop(wallet.publicKey, 2 * LAMPORTS_PER_SOL)
.then(() => {
notify({
message: "Account funded.",
message: LABELS.ACCOUNT_FUNDED,
type: "success",
});
});
@ -40,12 +42,11 @@ export const FaucetView = () => {
}}
>
<div className="deposit-input-title" style={{ margin: 10 }}>
This Faucet will help you fund your accounts outside of Solana main
network.
{LABELS.FAUCET_INFO}
</div>
<Button type="primary" onClick={airdrop}>
Give me SOL
</Button>
<ConnectButton type="primary" onClick={airdrop}>
{LABELS.GIVE_SOL}
</ConnectButton>
</div>
</Card>
</div>

View File

@ -1,12 +1,13 @@
import React from "react";
import { useTokenName } from "../../hooks";
import { LendingReserve } from "../../models/lending";
import { calculateBorrowAPY, LendingReserve } from "../../models/lending";
import { TokenIcon } from "../../components/TokenIcon";
import { decimalToLamports, formatNumber, fromLamports } from "../../utils/utils";
import { wadToLamports, formatNumber, fromLamports } 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;
@ -21,7 +22,8 @@ export const LendingReserveItem = (props: {
liquidityMint
);
const totalBorrows = decimalToLamports(props.reserve.totalBorrows).toNumber();
console.log(props.reserve.totalBorrowsWad.toString());
const totalBorrows = fromLamports(wadToLamports(props.reserve.totalBorrowsWad), liquidityMint);
console.log(liquidityMint);
@ -40,9 +42,12 @@ export const LendingReserveItem = (props: {
{formatNumber.format(totalBorrows)} {name}
</div>
<div>--</div>
<div>--</div>
<div>{calculateBorrowAPY(props.reserve)}</div>
</div>
</Card>
</Link>
);
};

View File

@ -12,11 +12,12 @@ import "./style.less";
export const RepayReserveView = () => {
const { reserve: reserveId, obligation: obligationId } = useParams<{
reserve: string;
reserve?: string;
obligation?: string;
}>();
const lendingReserve = useLendingReserve(reserveId);
const lendingObligation = useLendingObligation(obligationId);
const lendingReserve = useLendingReserve(obligationId ? lendingObligation?.info.borrowReserve : reserveId);
const reserve = lendingReserve?.info;
console.log([reserveId, obligationId]);