mango-ui-v3/components/CloseAccountModal.tsx

272 lines
8.6 KiB
TypeScript
Raw Normal View History

2021-11-09 07:58:29 -08:00
import {
2021-11-08 08:42:55 -08:00
FunctionComponent,
useCallback,
useEffect,
useMemo,
useState,
} from 'react'
import useMangoStore, { MNGO_INDEX, programId } from '../stores/useMangoStore'
import { XCircleIcon } from '@heroicons/react/outline'
import Button from './Button'
import Modal from './Modal'
import { ElementTitle } from './styles'
import { notify } from '../utils/notifications'
//import { useTranslation } from 'next-i18next'
import { CheckCircleIcon } from '@heroicons/react/solid'
import {
getMultipleAccounts,
makeCloseAdvancedOrdersInstruction,
makeCloseMangoAccountInstruction,
makeCloseSpotOpenOrdersInstruction,
nativeToUi,
zeroKey,
ZERO_BN,
ZERO_I80F48,
} from '@blockworks-foundation/mango-client'
import usePerpPositions from '../hooks/usePerpPositions'
import { Transaction } from '@solana/web3.js'
import useMangoGroupConfig from '../hooks/useMangoGroupConfig'
import { useOpenOrders } from '../hooks/useOpenOrders'
interface CloseAccountModalProps {
accountName?: string
lamports?: number
isOpen: boolean
onClose?: (x?) => void
}
const CloseAccountModal: FunctionComponent<CloseAccountModalProps> = ({
isOpen,
onClose,
}) => {
//const { t } = useTranslation('common')
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
const { openPositions, unsettledPositions } = usePerpPositions()
const [hasBorrows, setHasBorrows] = useState(false)
const [hasOpenPositions, setHasOpenPositions] = useState(false)
const [totalAccountSOL, setTotalAccountSOL] = useState(0)
const actions = useMangoStore((s) => s.actions)
const connection = useMangoStore((s) => s.connection.current)
const client = useMangoStore((s) => s.connection.client)
const groupConfig = useMangoGroupConfig()
const openOrders = useOpenOrders()
2021-11-09 07:58:29 -08:00
const setMangoStore = useMangoStore((s) => s.set)
const mangoAccounts = useMangoStore((s) => s.mangoAccounts)
2021-11-08 08:42:55 -08:00
const fetchTotalAccountSOL = useCallback(async () => {
if (!mangoAccount) {
return
}
const accountKeys = [
mangoAccount.publicKey,
...mangoAccount.spotOpenOrders.filter((oo) => !oo.equals(zeroKey)),
...(!mangoAccount.advancedOrdersKey.equals(zeroKey)
? [mangoAccount.advancedOrdersKey]
: []),
]
const accounts = await getMultipleAccounts(connection, accountKeys)
const lamports =
accounts.reduce((total, account) => {
return total + account.accountInfo.lamports
}, 0) * 0.000000001
setTotalAccountSOL(lamports)
}, [mangoAccount])
useEffect(() => {
if (mangoAccount) {
if (mangoAccount.borrows.some((b) => b.gt(ZERO_I80F48))) {
setHasBorrows(true)
}
if (openPositions.length || unsettledPositions.length) {
setHasOpenPositions(true)
}
}
fetchTotalAccountSOL()
}, [mangoAccount])
const mngoAccrued = useMemo(() => {
return mangoAccount
? mangoAccount.perpAccounts.reduce((acc, perpAcct) => {
return perpAcct.mngoAccrued.add(acc)
}, ZERO_BN)
: ZERO_BN
}, [mangoAccount])
const closeAccount = async () => {
const wallet = useMangoStore.getState().wallet.current
try {
console.log('withdrawAll')
await client.withdrawAll(mangoGroup, mangoAccount, wallet)
console.log('resolveAllDust')
await client.resolveAllDust(mangoGroup, mangoAccount, mangoCache, wallet)
const tx = new Transaction()
for (let i = 0; i < mangoAccount.spotOpenOrders.length; i++) {
const openOrders = mangoAccount.spotOpenOrders[i]
const spotMarket = groupConfig.spotMarkets[i]
if (!openOrders.equals(zeroKey)) {
tx.add(
makeCloseSpotOpenOrdersInstruction(
programId,
mangoGroup.publicKey,
mangoAccount.publicKey,
wallet.publicKey,
mangoGroup.dexProgramId,
openOrders,
spotMarket.publicKey,
mangoGroup.signerKey
)
)
}
}
if (!mangoAccount.advancedOrdersKey.equals(zeroKey)) {
tx.add(
makeCloseAdvancedOrdersInstruction(
programId,
mangoGroup.publicKey,
mangoAccount.publicKey,
wallet.publicKey,
mangoAccount.advancedOrdersKey
)
)
}
tx.add(
makeCloseMangoAccountInstruction(
programId,
mangoGroup.publicKey,
mangoAccount.publicKey,
wallet.publicKey
)
)
const txid = await client.sendTransaction(tx, wallet, [])
console.log('fetchAllMangoAccounts')
actions.fetchAllMangoAccounts()
console.log('setSelectedAccount')
2021-11-09 07:58:29 -08:00
setMangoStore((state) => {
state.selectedMangoAccount.current = mangoAccounts[0]
})
2021-11-08 08:42:55 -08:00
console.log('reloadMangoAccount')
actions.reloadMangoAccount()
onClose()
notify({
title: 'Account Deleted',
txid,
})
} catch (err) {
console.warn('Error deleting account:', err)
notify({
title: 'Error deleting account',
description: `${err}`,
txid: err.txid,
type: 'error',
})
}
}
return (
<Modal onClose={onClose} isOpen={isOpen && mangoAccount !== undefined}>
<Modal.Header>
<div className="flex items-center">
<ElementTitle noMarignBottom>Close your account</ElementTitle>
</div>
</Modal.Header>
<div className="text-th-fgd-2 text-center my-4">
You can close your Mango account and recover the small amount of SOL
used to cover rent exemption.
</div>
<div className="text-th-fgd-2 text-center my-4">
To close your account you must:
</div>
<div className="bg-th-bkg-4 overflow-none p-2 sm:p-6 rounded-lg">
<div className="flex items-center text-th-fgd-2 mb-4 ">
{!hasBorrows ? (
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
) : (
<XCircleIcon className="h-4 w-4 mr-1.5 text-th-red" />
)}{' '}
Close all borrows
</div>
<div className="flex items-center text-th-fgd-2 mb-4">
{!hasOpenPositions ? (
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
) : (
<XCircleIcon className="h-4 w-4 mr-1.5 text-th-red" />
)}{' '}
Close and settle all Perp positons
</div>
<div className="flex items-center text-th-fgd-2">
{openOrders && !openOrders.length ? (
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
) : (
<XCircleIcon className="h-4 w-4 mr-1.5 text-th-red" />
)}{' '}
Close all open orders
</div>
</div>
<div className="text-th-fgd-2 text-center my-4">
By closing your account you will:
</div>
<div className="bg-th-bkg-4 overflow-wrap p-2 sm:p-6 rounded-lg">
<div className="flex items-center text-th-fgd-2">
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
Delete your Mango account
</div>
{mangoAccount &&
mangoAccount.getAssetsVal(mangoGroup, mangoCache).gt(ZERO_I80F48) ? (
<div className="flex items-center text-th-fgd-2 mt-4">
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
Withdraw assets worth $
{mangoAccount.getAssetsVal(mangoGroup, mangoCache).toFixed(2)}
</div>
) : (
''
)}
<div className="flex items-center text-th-fgd-2 mt-4">
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
Recover {totalAccountSOL.toFixed(3)} SOL
</div>
{!mngoAccrued.isZero() ? (
<div className="flex items-center text-th-fgd-2 mt-4">
<CheckCircleIcon className="h-4 w-4 mr-1.5 text-th-green" />
Claim{' '}
{mangoGroup
? nativeToUi(
mngoAccrued.toNumber(),
mangoGroup.tokens[MNGO_INDEX].decimals
).toFixed(3)
: 0}{' '}
MNGO in unclaimed rewards
</div>
) : (
''
)}
</div>
<div className="text-th-fgd-2 text-center my-4">
Goodbye and good luck 🙏
</div>
<Button
onClick={() => closeAccount()}
disabled={
(openOrders && openOrders.length > 0) ||
hasBorrows ||
hasOpenPositions
}
className="mt-4 w-full"
>
Close Account
</Button>
</Modal>
)
}
export default CloseAccountModal