import BigNumber from 'bignumber.js' import { useCallback, useEffect, useState } from 'react' import AccountSummary from 'components/Account/AccountSummary' import AssetImage from 'components/AssetImage' import Button from 'components/Button' import Card from 'components/Card' import DisplayCurrency from 'components/DisplayCurrency' import Divider from 'components/Divider' import { FormattedNumber } from 'components/FormattedNumber' import { ArrowRight } from 'components/Icons' import Modal from 'components/Modal' import Switch from 'components/Switch' import Text from 'components/Text' import TitleAndSubCell from 'components/TitleAndSubCell' import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider' import { BN_ZERO } from 'constants/math' import useAutoLend from 'hooks/useAutoLend' import useCurrentAccount from 'hooks/useCurrentAccount' import useHealthComputer from 'hooks/useHealthComputer' import useToggle from 'hooks/useToggle' import { useUpdatedAccount } from 'hooks/useUpdatedAccount' import { getDepositAndLendCoinsToSpend } from 'hooks/useUpdatedAccount/functions' import useStore from 'store' import { BNCoin } from 'types/classes/BNCoin' import { byDenom } from 'utils/array' import { formatPercent, formatValue } from 'utils/formatters' import { BN } from 'utils/helpers' import {getDebtAmountWithInterest} from 'utils/tokens' function getDebtAmount(modal: BorrowModal) { return BN((modal.marketData as BorrowMarketTableData)?.debt ?? 0).toString() } function getAssetLogo(modal: BorrowModal) { if (!modal.asset) return null return } interface Props { account: Account modal: BorrowModal } export default function BorrowModalController() { const account = useCurrentAccount() const modal = useStore((s) => s.borrowModal) if (account && modal) { return } return null } function BorrowModal(props: Props) { const { modal, account } = props const [amount, setAmount] = useState(BN_ZERO) const showTxLoader = useStore((s) => s.showTxLoader) const [borrowToWallet, setBorrowToWallet] = useToggle() const borrow = useStore((s) => s.borrow) const repay = useStore((s) => s.repay) const asset = modal.asset const isRepay = modal.isRepay ?? false const [max, setMax] = useState(BN_ZERO) const { simulateBorrow, simulateRepay } = useUpdatedAccount(account) const { autoLendEnabledAccountIds } = useAutoLend() const apr = modal.marketData?.borrowRate ?? '0' const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id) const { computeMaxBorrowAmount } = useHealthComputer(account) const totalDebt = BN(getDebtAmount(modal)) const totalDebtRepayAmount = getDebtAmountWithInterest(totalDebt, Number(apr)) function resetState() { setAmount(BN_ZERO) } async function onConfirmClick() { if (!asset) return let result const { lend } = getDepositAndLendCoinsToSpend( BNCoin.fromDenomAndBigNumber(asset.denom, amount), account, ) if (isRepay) { result = await repay({ accountId: account.id, coin: BNCoin.fromDenomAndBigNumber(asset.denom, amount), accountBalance: amount.isEqualTo(totalDebtRepayAmount), lend, }) } else { result = await borrow({ accountId: account.id, coin: BNCoin.fromDenomAndBigNumber(asset.denom, amount), borrowToWallet, }) } if (result) { resetState() useStore.setState({ borrowModal: null }) } } function onClose() { resetState() useStore.setState({ borrowModal: null }) } const handleChange = useCallback( (newAmount: BigNumber) => { const coin = BNCoin.fromDenomAndBigNumber(asset.denom, newAmount) if (!amount.isEqualTo(newAmount)) setAmount(newAmount) if (isRepay) { const repayCoin = coin.amount.isGreaterThan(totalDebt) ? BNCoin.fromDenomAndBigNumber(asset.denom, totalDebt) : coin simulateRepay(repayCoin) } }, [asset, amount, isRepay, simulateRepay, modal, totalDebt, totalDebtRepayAmount], ) useEffect(() => { if (!account) return if (isRepay) { const depositBalance = account.deposits.find(byDenom(asset.denom))?.amount ?? BN_ZERO const lendBalance = account.lends.find(byDenom(asset.denom))?.amount ?? BN_ZERO const maxBalance = depositBalance.plus(lendBalance) const maxRepayAmount = BigNumber.min(maxBalance, totalDebtRepayAmount) setMax(maxRepayAmount) return } const maxBorrowAmount = computeMaxBorrowAmount( asset.denom, borrowToWallet ? 'wallet' : 'deposit', ) setMax(BigNumber.min(maxBorrowAmount, modal.marketData?.liquidity?.amount || 0)) }, [ account, isRepay, modal, asset.denom, computeMaxBorrowAmount, borrowToWallet, apr, totalDebtRepayAmount, ]) useEffect(() => { if (amount.isGreaterThan(max)) { handleChange(max) setAmount(max) } }, [amount, max, handleChange]) useEffect(() => { if (isRepay) return const coin = BNCoin.fromDenomAndBigNumber(asset.denom, amount.isGreaterThan(max) ? max : amount) const target = borrowToWallet ? 'wallet' : isAutoLendEnabled ? 'lend' : 'deposit' simulateBorrow(target, coin) }, [isRepay, borrowToWallet, isAutoLendEnabled, simulateBorrow, asset, amount, max]) if (!modal || !asset) return null return ( {getAssetLogo(modal)} {isRepay ? 'Repay' : 'Borrow'} {asset.symbol} } headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b' contentClassName='flex flex-col' > Liquidity available {!isRepay && ( <> Receive funds to Wallet Your borrowed funds will directly go to your wallet > )} } /> ) }