import { ArrowUpTrayIcon, ExclamationCircleIcon, // ExclamationCircleIcon, } from '@heroicons/react/20/solid' import Decimal from 'decimal.js' import { useTranslation } from 'next-i18next' import { useCallback, useMemo, useState } from 'react' import NumberFormat from 'react-number-format' import mangoStore from '@store/mangoStore' import { DEPOSIT_WITHDRAW_MODAL_INNER_HEIGHT, INPUT_TOKEN_DEFAULT, } from './../utils/constants' import { notify } from './../utils/notifications' import ActionTokenList from './account/ActionTokenList' import ButtonGroup from './forms/ButtonGroup' import Label from './forms/Label' import Button from './shared/Button' import Loading from './shared/Loading' import { EnterBottomExitBottom, FadeInFadeOut } from './shared/Transitions' import { withValueLimit } from './swap/MarketSwapForm' import { getMaxWithdrawForBank } from './swap/useTokenMax' import MaxAmountButton from '@components/shared/MaxAmountButton' import HealthImpactTokenChange from '@components/HealthImpactTokenChange' import useMangoAccount from 'hooks/useMangoAccount' import useMangoGroup from 'hooks/useMangoGroup' import TokenVaultWarnings from '@components/shared/TokenVaultWarnings' import { useWallet } from '@solana/wallet-adapter-react' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' import useBanksWithBalances from 'hooks/useBanksWithBalances' import { isMangoError } from 'types' import TokenListButton from './shared/TokenListButton' import { ACCOUNT_ACTIONS_NUMBER_FORMAT_CLASSES, BackButton } from './BorrowForm' import TokenLogo from './shared/TokenLogo' import SecondaryConnectButton from './shared/SecondaryConnectButton' import { handleInputChange } from 'utils/account' import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions' import { HealthType } from '@blockworks-foundation/mango-v4' interface WithdrawFormProps { onSuccess: () => void token?: string } function WithdrawForm({ onSuccess, token }: WithdrawFormProps) { const { t } = useTranslation(['common', 'trade']) const { group } = useMangoGroup() const [inputAmount, setInputAmount] = useState('') const [submitting, setSubmitting] = useState(false) const [selectedToken, setSelectedToken] = useState( token || INPUT_TOKEN_DEFAULT, ) const [showTokenList, setShowTokenList] = useState(false) const [sizePercentage, setSizePercentage] = useState('') const { mangoAccount } = useMangoAccount() const { connected } = useWallet() const banks = useBanksWithBalances('maxWithdraw') const unsettledPerpPositions = useUnsettledPerpPositions() const bank = useMemo(() => { const group = mangoStore.getState().group return group?.banksMapByName.get(selectedToken)?.[0] }, [selectedToken]) const [tokenMax, decimals] = useMemo(() => { if (!bank || !mangoAccount || !group) return [new Decimal(0), undefined] const tokenMax = getMaxWithdrawForBank(group, bank, mangoAccount).toNumber() const decimals = floorToDecimal(tokenMax, bank.mintDecimals).toNumber() ? bank.mintDecimals : undefined const roundedMax = decimals ? floorToDecimal(tokenMax, decimals) : tokenMax // Note: Disable for now, not sure why this was added, we can re-renable with specific conditions when // need is realized // const balance = mangoAccount.getTokenBalanceUi(bank) // if (tokenMax < balance) { // adjustedTokenMax = tokenMax * 0.998 // } return [new Decimal(roundedMax), decimals] }, [mangoAccount, bank, group]) const handleSizePercentage = useCallback( (percentage: string) => { if (!bank) return setSizePercentage(percentage) let amount: Decimal if (percentage !== '100') { amount = new Decimal(tokenMax).mul(percentage).div(100) } else { amount = new Decimal(tokenMax) } setInputAmount(amount.toFixed()) }, [bank, decimals, tokenMax], ) const setMax = useCallback(() => { if (!bank) return setInputAmount(tokenMax.toFixed()) setSizePercentage('100') }, [bank, tokenMax]) const handleWithdraw = useCallback(async () => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const actions = mangoStore.getState().actions const withdrawAmount = parseFloat(inputAmount) if (!mangoAccount || !group || !bank) return setSubmitting(true) const withdrawAll = floorToDecimal(tokenMax, bank.mintDecimals).eq( new Decimal(inputAmount), ) || sizePercentage === '100' try { const { signature: tx, slot } = withdrawAll ? await client.tokenWithdrawAllDepositForMint( group, mangoAccount, bank.mint, ) : await client.tokenWithdraw( group, mangoAccount, bank.mint, withdrawAmount, false, ) notify({ title: 'Transaction confirmed', type: 'success', txid: tx, }) await actions.reloadMangoAccount(slot) setSubmitting(false) onSuccess() } catch (e) { console.error(e) setSubmitting(false) if (!isMangoError(e)) return notify({ title: 'Transaction failed', description: e.message, txid: e?.txid, type: 'error', }) } }, [tokenMax, bank, inputAmount, sizePercentage]) const handleSelectToken = useCallback((token: string) => { setSelectedToken(token) setShowTokenList(false) }, []) const showInsufficientBalance = inputAmount ? tokenMax.lt(new Decimal(inputAmount)) : false const maintProjectedHealth = useMemo(() => { const uiAmount = Number(inputAmount) const mangoAccount = mangoStore.getState().mangoAccount.current const group = mangoStore.getState().group if (!group || !mangoAccount || !bank) return 0 const mintPk = bank.mint const uiTokenAmount = uiAmount * -1 const projectedHealth = mangoAccount.simHealthRatioWithTokenPositionUiChanges( group, [{ mintPk, uiTokenAmount }], HealthType.maint, ) return projectedHealth! > 100 ? 100 : projectedHealth! < 0 ? 0 : Math.trunc(projectedHealth!) }, [tokenMax, bank, inputAmount, sizePercentage]) const showMaxWithdrawUnSettledPerpsExist = unsettledPerpPositions && unsettledPerpPositions.length > 0 && maintProjectedHealth == 0 return ( <> setShowTokenList(false)} />

{t('select-withdraw-token')}

{t('token')}

{t('available-balance')}

{bank ? : null}
} setShowList={setShowTokenList} />
handleInputChange( values, source, setInputAmount, setSizePercentage, ) } isAllowed={withValueLimit} />
handleSizePercentage(p)} values={['10', '25', '50', '75', '100']} unit="%" />
{bank ? (

{t('withdraw-amount')}

) : null}
{connected ? ( ) : ( )}
) } export default WithdrawForm