diff --git a/src/components/BorrowInput/index.tsx b/src/components/BorrowInput/index.tsx index dbdd27a..83dceba 100644 --- a/src/components/BorrowInput/index.tsx +++ b/src/components/BorrowInput/index.tsx @@ -1,27 +1,23 @@ -import React, { useCallback, useMemo, useState } from "react"; -import { - useTokenName, - useUserBalance, - useUserObligationByReserve, -} from "../../hooks"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; +import { useUserBalance, useUserObligationByReserve } from "../../hooks"; import { BorrowAmountType, LendingReserve, LendingReserveParser, } from "../../models"; -import { TokenIcon } from "../TokenIcon"; import { Card } from "antd"; import { cache, ParsedAccount } from "../../contexts/accounts"; -import { NumericInput } from "../Input/numeric"; import { useConnection } from "../../contexts/connection"; import { useWallet } from "../../contexts/wallet"; import { borrow } from "../../actions"; -import { CollateralSelector } from "./../CollateralSelector"; import "./style.less"; import { LABELS } from "../../constants"; import { ActionConfirmation } from "./../ActionConfirmation"; import { BackButton } from "./../BackButton"; import { ConnectButton } from "../ConnectButton"; +import CollateralInput from "../CollateralInput"; +import { ArrowDownOutlined } from "@ant-design/icons"; +import { useMidPriceInUSD } from "../../contexts/market"; export const BorrowInput = (props: { className?: string; @@ -30,6 +26,8 @@ export const BorrowInput = (props: { const connection = useConnection(); const { wallet } = useWallet(); const [value, setValue] = useState(""); + const [collateralValue, setCollateralValue] = useState(""); + const [lastTyped, setLastTyped] = useState("collateral"); const [pendingTx, setPendingTx] = useState(false); const [showConfirmation, setShowConfirmation] = useState(false); @@ -46,7 +44,57 @@ export const BorrowInput = (props: { return cache.get(id) as ParsedAccount; }, [collateralReserveKey]); - const name = useTokenName(borrowReserve?.info.liquidityMint); + const borrowPrice = useMidPriceInUSD( + borrowReserve.info.liquidityMint.toBase58() + ).price; + const collateralPrice = useMidPriceInUSD( + collateralReserve?.info.liquidityMint.toBase58() + )?.price; + + useEffect(() => { + if (collateralReserve && lastTyped === "collateral") { + const ltv = borrowReserve.info.config.loanToValueRatio / 100; + + if (collateralValue) { + const nCollateralValue = parseFloat(collateralValue); + const borrowInUSD = nCollateralValue * collateralPrice * ltv; + const borrowAmount = borrowInUSD / borrowPrice; + setValue(borrowAmount.toString()); + } else { + setValue(""); + } + } + }, [ + lastTyped, + collateralReserve, + collateralPrice, + borrowPrice, + borrowReserve, + collateralValue, + ]); + + useEffect(() => { + if (collateralReserve && lastTyped === "borrow") { + const ltv = borrowReserve.info.config.loanToValueRatio / 100; + + if (value) { + const nValue = parseFloat(value); + const borrowInUSD = nValue * borrowPrice; + const collateralAmount = borrowInUSD / ltv / collateralPrice; + setCollateralValue(collateralAmount.toString()); + } else { + setCollateralValue(""); + } + } + }, [ + lastTyped, + collateralReserve, + collateralPrice, + borrowPrice, + borrowReserve, + value, + ]); + const { accounts: fromAccounts } = useUserBalance( collateralReserve?.info.collateralMint ); @@ -87,6 +135,7 @@ export const BorrowInput = (props: { ); setValue(""); + setCollateralValue(""); setShowConfirmation(true); } catch { // TODO: @@ -126,32 +175,50 @@ export const BorrowInput = (props: { justifyContent: "space-around", }} > -
{LABELS.SELECT_COLLATERAL}
- - -
{LABELS.BORROW_QUESTION}
-
- - { - setValue(val); +
+ { + setCollateralValue(val?.toString() || ""); + setLastTyped("collateral"); }} - style={{ - fontSize: 20, - boxShadow: "none", - borderColor: "transparent", - outline: "transparent", + onCollateralReserve={(key) => { + setCollateralReserveKey(key); }} - placeholder="0.00" /> -
{name}
+
+ +
+ { + setValue(val?.toString() || ""); + setLastTyped("borrow"); + }} + disabled={true} + hideBalance={true} + />
{LABELS.DEPOSIT_QUESTION}
-
- - + { + setValue(val?.toString() || ""); }} - placeholder="0.00" + disabled={true} + hideBalance={true} /> -
{name}
; - collateralReserve?: ParsedAccount; + collateralReserve: ParsedAccount; obligation: EnrichedLendingObligation; }) => { const connection = useConnection(); const { wallet } = useWallet(); + const [lastTyped, setLastTyped] = useState("repay"); const [pendingTx, setPendingTx] = useState(false); const [showConfirmation, setShowConfirmation] = useState(false); + const [collateralValue, setCollateralValue] = useState(""); const repayReserve = props.borrowReserve; const obligation = props.obligation; @@ -45,7 +45,6 @@ export const RepayInput = (props: { const borrowAmount = fromLamports(borrowAmountLamports, liquidityMint); const collateralReserve = props.collateralReserve; - const name = useTokenName(repayReserve?.info.liquidityMint); const { accounts: fromAccounts } = useUserBalance( repayReserve.info.liquidityMint ); @@ -54,10 +53,11 @@ export const RepayInput = (props: { const convert = useCallback( (val: string | number) => { + setLastTyped("repay"); if (typeof val === "string") { return (parseFloat(val) / borrowAmount) * 100; } else { - return ((val * borrowAmount) / 100).toFixed(2); + return (val * borrowAmount) / 100; } }, [borrowAmount] @@ -85,7 +85,6 @@ export const RepayInput = (props: { : Math.ceil( borrowAmountLamports * (parseFloat(value) / borrowAmount) ); - await repay( fromAccounts[0], toRepayLamports, @@ -98,6 +97,7 @@ export const RepayInput = (props: { ); setValue(""); + setCollateralValue(""); setShowConfirmation(true); } catch (error) { notify({ @@ -125,6 +125,53 @@ export const RepayInput = (props: { setValue, ]); + const collateralPrice = useMidPriceInUSD( + collateralReserve?.info.liquidityMint.toBase58() + )?.price; + + useEffect(() => { + if (collateralReserve && lastTyped === "repay") { + const collateralInQuote = obligation.info.collateralInQuote; + const collateral = collateralInQuote * collateralPrice; + if (value) { + const borrowRatio = (parseFloat(value) / borrowAmount) * 100; + const collateralAmount = (borrowRatio * collateral) / 100; + setCollateralValue(collateralAmount.toString()); + } else { + setCollateralValue(""); + } + } + }, [ + lastTyped, + collateralReserve, + obligation.info.collateralInQuote, + collateralPrice, + borrowAmount, + value, + ]); + + useEffect(() => { + if (collateralReserve && lastTyped === "collateral") { + const collateralInQuote = obligation.info.collateralInQuote; + const collateral = collateralInQuote * collateralPrice; + if (collateralValue) { + const collateralRatio = + (parseFloat(collateralValue) / collateral) * 100; + const borrowValue = (collateralRatio * borrowAmount) / 100; + setValue(borrowValue.toString()); + } else { + setValue(""); + } + } + }, [ + lastTyped, + collateralReserve, + obligation.info.collateralInQuote, + collateralPrice, + borrowAmount, + collateralValue, + ]); + const bodyStyle: React.CSSProperties = { display: "flex", flex: 1, @@ -145,33 +192,50 @@ export const RepayInput = (props: { justifyContent: "space-around", }} > -
{LABELS.REPAY_QUESTION}
-
- - + { + setValue(val?.toString() || ""); + setLastTyped("repay"); }} - placeholder="0.00" + disabled={true} + hideBalance={true} /> -
{name}
-
{LABELS.COLLATERAL}
- - +
+ { + setCollateralValue(val?.toString() || ""); + setLastTyped("collateral"); + }} + disabled={true} + hideBalance={true} + /> +
{LABELS.WITHDRAW_QUESTION}
-
- - + { + setValue(val?.toString() || ""); }} - placeholder="0.00" + disabled={true} + hideBalance={true} /> -
{name}
{ }; // Do not add pools here, causes a really bad infinite rendering loop. Use poolKeys instead. }, [ + pools, tokenMap, dailyVolume, poolKeys, diff --git a/src/views/repayReserve/index.tsx b/src/views/repayReserve/index.tsx index ca2d003..8a07493 100644 --- a/src/views/repayReserve/index.tsx +++ b/src/views/repayReserve/index.tsx @@ -37,7 +37,7 @@ export const RepayReserveView = () => { const reserve = lendingReserve?.info; - if (!reserve || !lendingReserve || !lendingObligation) { + if (!reserve || !lendingReserve || !lendingObligation || !repayReserve) { return null; }