import { Switch } from '@headlessui/react' import BigNumber from 'bignumber.js' import classNames from 'classnames' import React, { useEffect, useMemo, useState } from 'react' import { toast } from 'react-toastify' import { BorrowCapacity } from 'components/BorrowCapacity' import Button from 'components/Button' import CircularProgress from 'components/CircularProgress' import FormattedNumber from 'components/FormattedNumber' import Gauge from 'components/Gauge' import Modal from 'components/Modal' import Slider from 'components/Slider' import Text from 'components/Text' import useWithdrawFunds from 'hooks/mutations/useWithdrawFunds' import useAccountStats, { AccountStatsAction } from 'hooks/useAccountStats' 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 { chain } from 'utils/chains' import { formatValue } from 'utils/formatters' import { getTokenDecimals, getTokenSymbol } from 'utils/tokens' interface Props { open: boolean setOpen: (open: boolean) => void } const WithdrawModal = ({ open, setOpen }: Props) => { 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: () => { setOpen(false) 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)} onBlur={(e) => { if (e.target.value === '') setAmount(0) }} />
Available: {formatValue(maxWithdrawAmount, 0, 4, true, false, false, false, false)} { 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 Borrow assets from account to withdraw to your wallet
Account {selectedAccount} {accountStats && (
Current Leverage:{' '} {formatValue(accountStats.currentLeverage, 0, 2, true, false, 'x')}
Max Leverage:{' '} {formatValue(accountStats.maxLeverage, 0, 2, true, false, 'x')} } /> Current Risk: {formatValue(accountStats.risk * 100, 0, 2, true, false, '%')} } />
)}
Total Position:
Total Liabilities:
Balances {isLoadingPositions ? (
Loading...
) : (
Asset Value Size APY
{positionsData?.coins.map((coin) => (
{getTokenSymbol(coin.denom)} -
))} {positionsData?.debts.map((coin) => (
{getTokenSymbol(coin.denom)}
))}
)}
) } export default WithdrawModal