import { Dialog, Switch, Transition } from '@headlessui/react' import BigNumber from 'bignumber.js' import React, { useMemo, useState } from 'react' import { NumericFormat } from 'react-number-format' import { toast } from 'react-toastify' import Button from 'components/Button' import CircularProgress from 'components/CircularProgress' import ContainerSecondary from 'components/ContainerSecondary' import ProgressBar from 'components/ProgressBar' import SemiCircleProgress from 'components/SemiCircleProgress' import Slider from 'components/Slider' import Text from 'components/Text' import Tooltip from 'components/Tooltip' import useBorrowFunds from 'hooks/mutations/useBorrowFunds' import useAccountStats, { AccountStatsAction } from 'hooks/useAccountStats' import useAllBalances from 'hooks/useAllBalances' import useCalculateMaxBorrowAmount from 'hooks/useCalculateMaxBorrowAmount' import useCreditAccountPositions from 'hooks/useCreditAccountPositions' import useMarkets from 'hooks/useMarkets' import useTokenPrices from 'hooks/useTokenPrices' import useCreditManagerStore from 'stores/useCreditManagerStore' import { chain } from 'utils/chains' import { formatCurrency } from 'utils/formatters' import { getTokenDecimals, getTokenSymbol } from 'utils/tokens' type Props = { show: boolean onClose: () => void tokenDenom: string } const BorrowModal = ({ show, onClose, tokenDenom }: Props) => { const [amount, setAmount] = useState(0) const [isBorrowToCreditAccount, setIsBorrowToCreditAccount] = useState(false) const selectedAccount = useCreditManagerStore((s) => s.selectedAccount) const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions( selectedAccount ?? '', ) const { actions, borrowAmount } = useMemo(() => { const borrowAmount = BigNumber(amount) .times(10 ** getTokenDecimals(tokenDenom)) .toNumber() const withdrawAmount = isBorrowToCreditAccount ? 0 : borrowAmount return { borrowAmount, withdrawAmount, actions: [ { type: 'borrow', amount: borrowAmount, denom: tokenDenom, }, { type: 'withdraw', amount: withdrawAmount, denom: tokenDenom, }, ] as AccountStatsAction[], } }, [amount, isBorrowToCreditAccount, tokenDenom]) const accountStats = useAccountStats(actions) const tokenSymbol = getTokenSymbol(tokenDenom) const { mutate, isLoading } = useBorrowFunds(borrowAmount, tokenDenom, !isBorrowToCreditAccount, { onSuccess: () => { onClose() toast.success(`${amount} ${tokenSymbol} successfully Borrowed`) }, }) const { data: tokenPrices } = useTokenPrices() const { data: balancesData } = useAllBalances() const { data: marketsData } = useMarkets() const handleSubmit = () => { mutate() } const walletAmount = useMemo(() => { return BigNumber(balancesData?.find((balance) => balance.denom === tokenDenom)?.amount ?? 0) .div(10 ** getTokenDecimals(tokenDenom)) .toNumber() }, [balancesData, tokenDenom]) const tokenPrice = tokenPrices?.[tokenDenom] ?? 0 const borrowRate = Number(marketsData?.[tokenDenom]?.borrow_rate) const maxValue = useCalculateMaxBorrowAmount(tokenDenom, isBorrowToCreditAccount) const percentageValue = useMemo(() => { if (isNaN(amount) || maxValue === 0) return 0 return (amount * 100) / maxValue }, [amount, maxValue]) const handleValueChange = (value: number) => { if (value > maxValue) { setAmount(maxValue) return } setAmount(value) } const handleSliderValueChange = (value: number[]) => { const decimal = value[0] / 100 const tokenDecimals = getTokenDecimals(tokenDenom) // limit decimal precision based on token contract decimals const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals)) setAmount(newAmount) } const handleBorrowTargetChange = () => { setIsBorrowToCreditAccount((c) => !c) // reset amount due to max value calculations changing depending on borrow target setAmount(0) } const getTokenTotalUSDValue = (amount: string, denom: string) => { // early return if prices are not fetched yet if (!tokenPrices) return 0 return ( BigNumber(amount) .div(10 ** getTokenDecimals(denom)) .toNumber() * tokenPrices[denom] ) } return (
{isLoading && (
)}
Borrow {tokenSymbol}

In wallet: {walletAmount.toLocaleString()} {tokenSymbol}

Borrow Rate: {(borrowRate * 100).toFixed(2)}%

Amount

handleValueChange(v.floatValue || 0)} suffix={` ${tokenSymbol}`} decimalScale={getTokenDecimals(tokenDenom)} />
1 {tokenSymbol} = {formatCurrency(tokenPrice)}
{formatCurrency(tokenPrice * amount)}
setAmount(maxValue)} />
Borrow to Credit Account{' '} OFF = Borrow directly into your wallet by using your account Assets as collateral. The borrowed asset will become a liability in your account. ON = Borrow into your Account. The borrowed asset will be available in the account as an Asset and appear also as a liability in your account. } />

About

Subaccount {selectedAccount}

{accountStats && (

{formatCurrency( BigNumber(accountStats.netWorth) .dividedBy(10 ** chain.stakeCurrency.coinDecimals) .toNumber(), )}

{/* TOOLTIP */}
)}
Total Position:
{formatCurrency( BigNumber(accountStats?.totalPosition ?? 0) .dividedBy(10 ** chain.stakeCurrency.coinDecimals) .toNumber(), )}
Total Liabilities:
{formatCurrency( BigNumber(accountStats?.totalDebt ?? 0) .dividedBy(10 ** chain.stakeCurrency.coinDecimals) .toNumber(), )}

Balances

{isLoadingPositions ? (
Loading...
) : ( {positionsData?.coins.map((coin) => ( ))} {positionsData?.debts.map((coin) => ( ))}
Asset Value Size APY
{getTokenSymbol(coin.denom)} {formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))} {BigNumber(coin.amount) .div(10 ** getTokenDecimals(coin.denom)) .toNumber() .toLocaleString(undefined, { maximumFractionDigits: getTokenDecimals(coin.denom), })} -
{getTokenSymbol(coin.denom)} -{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))} - {BigNumber(coin.amount) .div(10 ** getTokenDecimals(coin.denom)) .toNumber() .toLocaleString(undefined, { maximumFractionDigits: 6, })} -{(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}%
)}
) } export default BorrowModal