import { HealthType } from '@blockworks-foundation/mango-v4' import { ArrowLeftIcon, ArrowUpLeftIcon, ArrowUpTrayIcon, ExclamationCircleIcon, } from '@heroicons/react/20/solid' import Decimal from 'decimal.js' import { useTranslation } from 'next-i18next' import React, { useCallback, useMemo, useState } from 'react' import NumberFormat, { NumberFormatValues, SourceInfo, } from 'react-number-format' import mangoStore from '@store/mangoStore' import { ACCOUNT_ACTION_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 InlineNotification from './shared/InlineNotification' 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 Tooltip from '@components/shared/Tooltip' import useMangoAccount from 'hooks/useMangoAccount' import useMangoGroup from 'hooks/useMangoGroup' import TokenVaultWarnings from '@components/shared/TokenVaultWarnings' import { useWallet } from '@solana/wallet-adapter-react' import FormatNumericValue from './shared/FormatNumericValue' 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 TokenLogo from './shared/TokenLogo' import SecondaryConnectButton from './shared/SecondaryConnectButton' interface BorrowFormProps { onSuccess: () => void token?: string } export const ACCOUNT_ACTIONS_NUMBER_FORMAT_CLASSES = 'w-full rounded-lg rounded-l-none border border-th-input-border bg-th-input-bkg p-3 text-right font-mono text-xl text-th-fgd-1 focus-visible:border-th-fgd-4 focus:outline-none md:hover:border-th-input-border-hover md:hover:focus-visible:border-th-fgd-4' function BorrowForm({ onSuccess, token }: BorrowFormProps) { const { t } = useTranslation('common') 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, publicKey } = useWallet() const banks = useBanksWithBalances('maxBorrow') const bank = useMemo(() => { const group = mangoStore.getState().group return group?.banksMapByName.get(selectedToken)?.[0] }, [selectedToken]) const tokenMax = useMemo(() => { const group = mangoStore.getState().group if (!group || !bank || !mangoAccount) return new Decimal(0) const amount = getMaxWithdrawForBank(group, bank, mangoAccount, true) return amount && amount.gt(0) ? new Decimal(amount) : new Decimal(0) }, [mangoAccount, bank]) const tokenBalance = useMemo(() => { if (!bank || !mangoAccount) return new Decimal(0) const balance = new Decimal(mangoAccount.getTokenBalanceUi(bank)) return balance.gt(0) ? balance : new Decimal(0) }, [bank, mangoAccount]) const isBorrow = parseFloat(inputAmount) > tokenBalance.toNumber() const handleSizePercentage = useCallback( (percentage: string) => { if (!bank) return setSizePercentage(percentage) const amount = floorToDecimal( new Decimal(percentage).div(100).mul(tokenMax), bank.mintDecimals, ) setInputAmount(amount.toFixed()) }, [tokenMax, bank], ) const setMax = useCallback(() => { if (!bank) return const max = floorToDecimal(tokenMax, bank.mintDecimals) setInputAmount(max.toFixed()) handleSizePercentage('100') }, [bank, tokenMax, handleSizePercentage]) const handleSelectToken = (token: string) => { setSelectedToken(token) setShowTokenList(false) } const handleBorrow = useCallback(async () => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const actions = mangoStore.getState().actions if (!mangoAccount || !group || !publicKey) return setSubmitting(true) try { const { signature: tx, slot } = await client.tokenWithdraw( group, mangoAccount, bank!.mint, Number(inputAmount), true, ) notify({ title: 'Transaction confirmed', type: 'success', txid: tx, }) await actions.reloadMangoAccount(slot) actions.fetchWalletTokens(publicKey) 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', }) } }, [bank, inputAmount, onSuccess, publicKey]) const handleInputChange = (e: NumberFormatValues, info: SourceInfo) => { if (info.source === 'event') { setSizePercentage('') } setInputAmount(!Number.isNaN(Number(e.value)) ? e.value : '') } const initHealth = useMemo(() => { return group && mangoAccount ? mangoAccount.getHealthRatioUi(group, HealthType.init) : 100 }, [mangoAccount, group]) const showInsufficientBalance = Number(inputAmount) ? tokenMax.lt(inputAmount) : false return ( <> setShowTokenList(false)} />

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

{t('token')}

{t('borrow-rate')}

{t('max-borrow')}

{initHealth <= 0 ? (
) : null} {bank ? : null}
} setShowList={setShowTokenList} />
handleSizePercentage(p)} values={['10', '25', '50', '75', '100']} unit="%" />
{/*

{t('leverage')}

0.00x

setInputAmount(x)} />
*/}
{bank ? (

{t('withdraw-amount')}

{isBorrow ? ( ) : ( )}

{t('borrow-amount')}

{t('loan-origination-fee')}

{isBorrow ? ( <> {' '} {bank.name} ) : ( 'N/A' )}

) : null}
{connected ? ( ) : ( )}
) } export default BorrowForm export const BackButton = ({ onClick }: { onClick: (x: boolean) => void }) => { return ( ) }