import { ArrowDownRightIcon, ArrowLeftIcon, ChevronDownIcon, ExclamationCircleIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid' import { useWallet } from '@solana/wallet-adapter-react' import Decimal from 'decimal.js' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' import React, { useCallback, useEffect, useMemo, useState } from 'react' import NumberFormat, { NumberFormatValues } from 'react-number-format' import mangoStore from '@store/mangoStore' import { notify } from './../utils/notifications' import { floorToDecimal, formatDecimal, formatFixedDecimals, } from './../utils/numbers' 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/SwapForm' import MaxAmountButton from '@components/shared/MaxAmountButton' import HealthImpactTokenChange from '@components/HealthImpactTokenChange' import { useAlphaMax, walletBalanceForToken } from './DepositForm' import SolBalanceWarnings from '@components/shared/SolBalanceWarnings' import useMangoAccount from 'hooks/useMangoAccount' import useJupiterMints from 'hooks/useJupiterMints' import useMangoGroup from 'hooks/useMangoGroup' import { ACCOUNT_ACTION_MODAL_INNER_HEIGHT, INPUT_TOKEN_DEFAULT, } from 'utils/constants' import ConnectEmptyState from './shared/ConnectEmptyState' import AmountWithValue from './shared/AmountWithValue' interface RepayFormProps { onSuccess: () => void token?: string } function RepayForm({ onSuccess, token }: RepayFormProps) { const { t } = useTranslation('common') const { group } = useMangoGroup() const { mangoAccount } = useMangoAccount() 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 { mangoTokens } = useJupiterMints() // const { maxSolDeposit } = useSolBalance() const bank = useMemo(() => { const group = mangoStore.getState().group return group?.banksMapByName.get(selectedToken)?.[0] }, [selectedToken]) const logoUri = useMemo(() => { let logoURI if (mangoTokens.length && bank) { logoURI = mangoTokens.find( (t) => t.address === bank?.mint.toString() )?.logoURI } return logoURI }, [bank, mangoTokens]) const { connected, publicKey } = useWallet() const walletTokens = mangoStore((s) => s.wallet.tokens) const walletBalance = useMemo(() => { return selectedToken ? walletBalanceForToken(walletTokens, selectedToken) : { maxAmount: 0, maxDecimals: 6 } }, [walletTokens, selectedToken]) const borrowAmount = useMemo(() => { if (!mangoAccount || !bank) return 0 return floorToDecimal( mangoAccount.getTokenBorrowsUi(bank), bank.mintDecimals ).toNumber() }, [bank, mangoAccount]) const setMax = useCallback(() => { if (!bank) return setInputAmount(floorToDecimal(borrowAmount, bank.mintDecimals).toFixed()) setSizePercentage('100') }, [bank, borrowAmount]) const handleSizePercentage = useCallback( (percentage: string) => { if (!bank) return setSizePercentage(percentage) let amount: Decimal | number = new Decimal(borrowAmount) .mul(percentage) .div(100) amount = floorToDecimal(amount, bank.mintDecimals).toNumber() setInputAmount(amount.toFixed(bank.mintDecimals)) }, [bank, borrowAmount] ) const handleSelectToken = (token: string) => { setSelectedToken(token) setShowTokenList(false) } const handleDeposit = useCallback( async (amount: string) => { //to not leave some dust on account we round amount by this number //with reduce only set to true we take only what is needed to be //deposited in need to repay borrow const mangoAccount = mangoStore.getState().mangoAccount.current const client = mangoStore.getState().client const group = mangoStore.getState().group const actions = mangoStore.getState().actions if (!mangoAccount || !group || !bank || !publicKey) return //we don't want to left negative dust in account if someone wants to repay full amount const actualAmount = sizePercentage === '100' ? mangoAccount.getTokenBorrowsUi(bank) < parseFloat(amount) ? parseFloat(amount) : mangoAccount.getTokenBorrowsUi(bank) : parseFloat(amount) setSubmitting(true) try { const tx = await client.tokenDeposit( group, mangoAccount, bank.mint, actualAmount, true ) notify({ title: 'Transaction confirmed', type: 'success', txid: tx, }) await actions.reloadMangoAccount() actions.fetchWalletTokens(publicKey) setSubmitting(false) onSuccess() } catch (e: any) { notify({ title: 'Transaction failed', description: e.message, txid: e?.txid, type: 'error', }) console.error('Error repaying:', e) setSubmitting(false) } }, [bank, publicKey?.toBase58(), sizePercentage] ) const banks = useMemo(() => { const banks = group?.banksMapByName && mangoAccount ? Array.from(group?.banksMapByName, ([key, value]) => { return { key, value, borrowAmount: floorToDecimal( mangoAccount?.getTokenBorrowsUi(value[0]), value[0].mintDecimals ).toNumber(), borrowAmountValue: mangoAccount?.getTokenBorrowsUi(value[0]) * value[0].uiPrice!, } }).filter((b) => b.borrowAmount > 0) : [] return banks }, [group?.banksMapByName, mangoAccount]) useEffect(() => { if (!token && banks.length) { setSelectedToken(banks[0].key) } }, [token, banks]) const exceedsAlphaMax = useAlphaMax(inputAmount, bank) const showInsufficientBalance = walletBalance.maxAmount < Number(inputAmount) return banks.length ? ( <>

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

{t('token')}

{t('amount-owed')}

{ setInputAmount( !Number.isNaN(Number(e.value)) ? e.value : '' ) }} isAllowed={withValueLimit} />
handleSizePercentage(p)} values={['10', '25', '50', '75', '100']} unit="%" />
{bank ? (

{t('repayment-amount')}

{inputAmount ? ( ) : ( )}

{t('outstanding-balance')}

{floorToDecimal( borrowAmount - Number(inputAmount), walletBalance.maxDecimals ).toFixed()}{' '} {selectedToken}

) : null}
) : !connected ? (
) : (
😎

No borrows to repay...

) } export default RepayForm