import { Dialog, Switch, Transition } from '@headlessui/react' import * as RSlider from '@radix-ui/react-slider' import BigNumber from 'bignumber.js' import React, { useEffect, useMemo, useState } from 'react' import { toast } from 'react-toastify' import Slider from 'components/Slider' import useWithdrawFunds from 'hooks/mutations/useWithdrawFunds' import useAllBalances from 'hooks/useAllBalances' import useCalculateMaxWithdrawAmount from 'hooks/useCalculateMaxWithdrawAmount' import useCreditAccountPositions from 'hooks/useCreditAccountPositions' import useMarkets from 'hooks/useMarkets' import useTokenPrices from 'hooks/useTokenPrices' import useCreditManagerStore from 'stores/useCreditManagerStore' import { formatCurrency } from 'utils/formatters' import { getTokenDecimals, getTokenSymbol } from 'utils/tokens' import useAccountStats, { AccountStatsAction } from 'hooks/useAccountStats' import { chain } from 'utils/chains' import Spinner from './Spinner' import SemiCircleProgress from './SemiCircleProgress' import ProgressBar from './ProgressBar' import ContainerSecondary from './ContainerSecondary' import Button from './Button' const WithdrawModal = ({ show, onClose }: any) => { const [amount, setAmount] = useState(0) const [selectedToken, setSelectedToken] = useState('') const [isBorrowEnabled, setIsBorrowEnabled] = useState(false) const selectedAccount = useCreditManagerStore((s) => s.selectedAccount) const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions( selectedAccount ?? '', ) const { data: balancesData } = useAllBalances() const { data: tokenPrices } = useTokenPrices() const { data: marketsData } = useMarkets() const selectedTokenSymbol = getTokenSymbol(selectedToken) const selectedTokenDecimals = getTokenDecimals(selectedToken) const tokenAmountInCreditAccount = useMemo(() => { return BigNumber(positionsData?.coins.find((coin) => coin.denom === selectedToken)?.amount ?? 0) .div(10 ** selectedTokenDecimals) .toNumber() }, [positionsData, selectedTokenDecimals, selectedToken]) const { actions, borrowAmount, withdrawAmount } = useMemo(() => { const borrowAmount = amount > tokenAmountInCreditAccount ? BigNumber(amount) .minus(tokenAmountInCreditAccount) .times(10 ** selectedTokenDecimals) .toNumber() : 0 const withdrawAmount = BigNumber(amount) .times(10 ** selectedTokenDecimals) .toNumber() return { borrowAmount, withdrawAmount, actions: [ { type: 'borrow', amount: borrowAmount, denom: selectedToken, }, { type: 'withdraw', amount: withdrawAmount, denom: selectedToken, }, ] as AccountStatsAction[], } }, [amount, selectedToken, selectedTokenDecimals, tokenAmountInCreditAccount]) const accountStats = useAccountStats(actions) const { mutate, isLoading } = useWithdrawFunds(withdrawAmount, borrowAmount, selectedToken, { onSuccess: () => { onClose() toast.success(`${amount} ${selectedTokenSymbol} successfully withdrawn`) }, }) const maxWithdrawAmount = useCalculateMaxWithdrawAmount(selectedToken, isBorrowEnabled) const walletAmount = useMemo(() => { if (!selectedToken) return 0 return BigNumber(balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0) .div(10 ** selectedTokenDecimals) .toNumber() }, [balancesData, selectedToken, selectedTokenDecimals]) useEffect(() => { if (positionsData && positionsData.coins.length > 0) { // initialize selected token when allowedCoins fetch data is available setSelectedToken(positionsData.coins[0].denom) } }, [positionsData]) const handleTokenChange = (e: React.ChangeEvent) => { setSelectedToken(e.target.value) if (e.target.value !== selectedToken) setAmount(0) } const handleValueChange = (value: number) => { if (value > maxWithdrawAmount) { setAmount(maxWithdrawAmount) return } setAmount(value) } const handleBorrowChange = () => { setIsBorrowEnabled((c) => !c) // reset amount due to max value calculations changing depending on wheter the user is borrowing or not 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] ) } const percentageValue = useMemo(() => { if (isNaN(amount) || maxWithdrawAmount === 0) return 0 return (amount * 100) / maxWithdrawAmount }, [amount, maxWithdrawAmount]) return (
{isLoading && (
)}
Withdraw from Account {selectedAccount}
Asset:
Amount:
handleValueChange(e.target.valueAsNumber)} />

In wallet: {walletAmount.toLocaleString()}

{ const decimal = value[0] / 100 // limit decimal precision based on token contract decimals const newAmount = Number( (decimal * maxWithdrawAmount).toFixed(selectedTokenDecimals), ) setAmount(newAmount) }} onMaxClick={() => setAmount(maxWithdrawAmount)} />

Withdraw with borrowing

Explanation....

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 WithdrawModal