mango-v4-ui/components/modals/CloseAccountModal.tsx

204 lines
7.1 KiB
TypeScript
Raw Normal View History

2022-07-28 03:51:36 -07:00
import { ModalProps } from '../../types/modal'
import Modal from '../shared/Modal'
2022-09-12 08:53:57 -07:00
import mangoStore from '@store/mangoStore'
2022-07-28 03:51:36 -07:00
import { notify } from '../../utils/notifications'
import Button from '../shared/Button'
import { useTranslation } from 'next-i18next'
2023-01-12 05:23:16 -08:00
import { useCallback, useEffect, useState } from 'react'
2022-07-28 03:51:36 -07:00
import BounceLoader from '../shared/BounceLoader'
2023-01-12 05:23:16 -08:00
import {
MangoAccount,
TokenPosition,
toUiDecimalsForQuote,
} from '@blockworks-foundation/mango-v4'
2023-01-25 03:26:21 -08:00
import { ExclamationCircleIcon, TrashIcon } from '@heroicons/react/20/solid'
2023-01-11 09:38:51 -08:00
import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions'
2023-01-12 05:23:16 -08:00
import { getMultipleAccounts } from '@project-serum/anchor/dist/cjs/utils/rpc'
2023-01-24 16:54:24 -08:00
import { formatCurrencyValue } from 'utils/numbers'
2022-07-28 03:51:36 -07:00
const CloseAccountModal = ({ isOpen, onClose }: ModalProps) => {
2023-01-12 05:23:16 -08:00
const { t } = useTranslation(['close-account'])
2022-07-28 03:51:36 -07:00
const [loading, setLoading] = useState(false)
2022-08-11 21:20:17 -07:00
const set = mangoStore((s) => s.set)
2023-01-11 09:38:51 -08:00
const openOrders = Object.values(mangoStore((s) => s.mangoAccount.openOrders))
2023-01-12 05:23:16 -08:00
const connection = mangoStore.getState().connection
2023-01-11 14:37:58 -08:00
const hasOpenOrders =
openOrders.length && openOrders.filter((x) => x.length).length > 0
2023-01-11 09:38:51 -08:00
const mangoAccount = mangoStore((s) => s.mangoAccount)
const perpPositions = mangoStore((s) => s.mangoAccount.perpPositions)
const openPerpPositions = Object.values(perpPositions).filter((p) =>
p.basePositionLots.toNumber()
)
2023-01-11 14:37:58 -08:00
const group = mangoStore.getState().group
2023-01-11 09:38:51 -08:00
const unsettledBalances = Object.values(mangoAccount.spotBalances).filter(
(x) => x.unsettled && x.unsettled > 0
)
const unsettledPerpPositions = useUnsettledPerpPositions()
2023-01-11 14:37:58 -08:00
const [hasBorrows, setHasBorrows] = useState(false)
2023-01-11 09:38:51 -08:00
const [hasOpenPositions, setHasOpenPositions] = useState(false)
2023-01-12 05:23:16 -08:00
const [totalAccountSOL, setTotalAccountSOL] = useState(0)
2022-07-28 03:51:36 -07:00
const handleCloseMangoAccount = async () => {
const client = mangoStore.getState().client
const mangoAccount = mangoStore.getState().mangoAccount.current
2022-10-07 04:47:15 -07:00
const mangoAccounts = mangoStore.getState().mangoAccounts
2023-01-11 09:38:51 -08:00
2022-07-28 03:51:36 -07:00
if (!mangoAccount || !group) return
setLoading(true)
try {
2023-01-13 09:07:18 -08:00
const tx = await client.emptyAndCloseMangoAccount(group, mangoAccount)
2022-07-28 03:51:36 -07:00
if (tx) {
const newMangoAccounts = mangoAccounts.filter(
(ma) => !ma.publicKey.equals(mangoAccount.publicKey)
)
let newCurrentAccount: MangoAccount
if (newMangoAccounts[0]) {
newCurrentAccount = await newMangoAccounts[0].reload(client)
}
2022-07-28 03:51:36 -07:00
setLoading(false)
onClose()
notify({
title: t('account-closed'),
type: 'success',
txid: tx,
})
2022-08-11 21:20:17 -07:00
set((state) => {
2022-10-07 04:47:15 -07:00
state.mangoAccounts = newMangoAccounts
state.mangoAccount.current = newCurrentAccount
2022-08-11 21:20:17 -07:00
})
2022-07-28 03:51:36 -07:00
}
} catch (e) {
setLoading(false)
2022-08-02 11:04:00 -07:00
console.error(e)
2022-07-28 03:51:36 -07:00
}
}
2023-01-12 05:23:16 -08:00
const fetchTotalAccountSOL = useCallback(async () => {
if (!mangoAccount) {
return
}
const accountKeys = [
mangoAccount.current!.publicKey,
...mangoAccount.openOrderAccounts.map((x) => x.address),
]
const accounts = await getMultipleAccounts(connection, accountKeys)
const lamports =
accounts.reduce((total, account) => {
2023-01-13 16:04:59 -08:00
return total + (account?.account.lamports || 0)
2023-01-12 05:23:16 -08:00
}, 0) * 0.000000001
setTotalAccountSOL(lamports)
}, [mangoAccount])
2023-01-11 09:38:51 -08:00
useEffect(() => {
2023-01-11 14:37:58 -08:00
if (mangoAccount && group) {
if (
mangoAccount.current
?.tokensActive()
2023-01-13 16:58:07 -08:00
.filter((token: TokenPosition) =>
token
.balance(group.getFirstBankByTokenIndex(token.tokenIndex))
.isNeg()
2023-01-11 14:37:58 -08:00
).length
) {
setHasBorrows(true)
}
2023-01-11 09:38:51 -08:00
if (openPerpPositions.length || unsettledPerpPositions.length) {
setHasOpenPositions(true)
}
2023-01-12 05:23:16 -08:00
fetchTotalAccountSOL()
2023-01-11 09:38:51 -08:00
}
2023-01-11 14:37:58 -08:00
}, [mangoAccount, group])
2023-01-11 09:38:51 -08:00
const isDisabled =
2023-01-11 14:37:58 -08:00
hasOpenOrders ||
2023-01-11 09:38:51 -08:00
hasBorrows ||
hasOpenPositions ||
!!unsettledBalances.length
2023-01-25 03:26:21 -08:00
2022-07-28 03:51:36 -07:00
return (
<Modal isOpen={isOpen} onClose={onClose}>
2023-01-25 03:26:21 -08:00
<div className="h-[268px]">
2022-07-28 03:51:36 -07:00
{loading ? (
<BounceLoader loadingMessage={t('closing-account')} />
) : (
<div className="flex h-full flex-col justify-between">
2023-01-25 03:26:21 -08:00
<div>
<h2 className="mb-2">{t('close-account')}</h2>
{!isDisabled ? (
<>
<p className="mb-3">{t('are-you-sure')}:</p>
<ol className="list-inside list-decimal space-y-1.5 border-y border-th-bkg-3 py-3 text-left">
<li>{t('delete-your-account')}</li>
<li>
{t('withdraw-assets-worth', {
value:
mangoAccount && group
2023-01-25 15:07:25 -08:00
? formatCurrencyValue(
2023-01-25 03:26:21 -08:00
toUiDecimalsForQuote(
2023-01-25 15:07:25 -08:00
mangoAccount!.current!.getEquity(group)
)
2023-01-25 03:26:21 -08:00
)
: 0,
})}
</li>
<li>
{t('recover-x-sol', {
amount: totalAccountSOL.toFixed(4),
})}
</li>
</ol>
</>
) : (
<>
<p className="mb-3">{t('you-must')}:</p>
<div className="space-y-1.5 border-y border-th-bkg-3 py-3">
{hasBorrows ? (
<div className="flex items-center">
<ExclamationCircleIcon className="mr-1.5 h-5 w-5 text-th-down" />
<p>{t('close-all-borrows')}</p>
</div>
) : null}
{hasOpenPositions ? (
<div className="flex items-center">
<ExclamationCircleIcon className="mr-1.5 h-5 w-5 text-th-down" />
<p>{t('close-perp-positions')}</p>
</div>
) : null}
{hasOpenOrders ? (
<div className="flex items-center">
<ExclamationCircleIcon className="mr-1.5 h-5 w-5 text-th-down" />
<p>{t('close-open-orders')}</p>
</div>
) : null}
{unsettledBalances.length ? (
<div className="flex items-center">
<ExclamationCircleIcon className="mr-1.5 h-5 w-5 text-th-down" />
<p>{t('settle-balances')}</p>
</div>
) : null}
</div>
</>
)}
2022-07-28 03:51:36 -07:00
</div>
<Button
className="w-full"
2023-01-11 14:37:58 -08:00
disabled={isDisabled}
2022-07-28 03:51:36 -07:00
onClick={handleCloseMangoAccount}
size="large"
>
2022-09-11 05:05:21 -07:00
<div className="flex items-center justify-center">
<TrashIcon className="mr-2 h-5 w-5" />
{t('close-account')}
</div>
2022-07-28 03:51:36 -07:00
</Button>
</div>
)}
</div>
</Modal>
)
}
export default CloseAccountModal