215 lines
7.7 KiB
TypeScript
215 lines
7.7 KiB
TypeScript
import { Bank } from '@blockworks-foundation/mango-v4'
|
|
import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
|
|
import Button, { LinkButton } from '@components/shared/Button'
|
|
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
|
import Modal from '@components/shared/Modal'
|
|
import TableRatesDisplay from '@components/shared/TableRatesDisplay'
|
|
import UnsettledTrades from '@components/trade/UnsettledTrades'
|
|
import { ArrowDownTrayIcon, ArrowUpTrayIcon } from '@heroicons/react/20/solid'
|
|
import mangoStore from '@store/mangoStore'
|
|
import useAccountInterest from 'hooks/useAccountInterest'
|
|
import useHealthContributions from 'hooks/useHealthContributions'
|
|
import useMangoAccount from 'hooks/useMangoAccount'
|
|
import useUnsettledPerpPositions from 'hooks/useUnsettledPerpPositions'
|
|
import { useTranslation } from 'next-i18next'
|
|
import { useMemo, useState } from 'react'
|
|
import { ModalProps } from 'types/modal'
|
|
import { formatCurrencyValue } from 'utils/numbers'
|
|
|
|
const ActionPanel = ({ bank }: { bank: Bank }) => {
|
|
const { t } = useTranslation(['common', 'trade'])
|
|
const { mangoAccount } = useMangoAccount()
|
|
const { initContributions } = useHealthContributions()
|
|
const [showDepositModal, setShowDepositModal] = useState<
|
|
'deposit' | 'withdraw' | ''
|
|
>('')
|
|
const [showSettleModal, setShowSettleModal] = useState(false)
|
|
const { data: totalInterestData } = useAccountInterest()
|
|
const [depositRate, borrowRate] = useMemo(() => {
|
|
const depositRate = bank.getDepositRateUi()
|
|
const borrowRate = bank.getBorrowRateUi()
|
|
return [depositRate, borrowRate]
|
|
}, [bank])
|
|
|
|
const collateralValue =
|
|
initContributions.find((val) => val.asset === bank.name)?.contribution || 0
|
|
const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances)
|
|
const inOrders = spotBalances[bank.mint.toString()]?.inOrders || 0
|
|
let unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0
|
|
const unsettledPerpPositions = useUnsettledPerpPositions()
|
|
|
|
if (bank.name === 'USDC' && unsettledPerpPositions?.length) {
|
|
const group = mangoStore.getState().group
|
|
const unsettledPositionValues = []
|
|
for (const position of unsettledPerpPositions) {
|
|
const market = group?.getPerpMarketByMarketIndex(position.marketIndex)
|
|
if (market) {
|
|
const posUnsettled = position.getUnsettledPnlUi(market)
|
|
unsettledPositionValues.push(posUnsettled)
|
|
}
|
|
}
|
|
unsettled = unsettled + unsettledPositionValues.reduce((a, c) => a + c, 0)
|
|
}
|
|
|
|
const symbol = bank.name === 'MSOL' ? 'mSOL' : bank.name
|
|
const hasInterestEarned = totalInterestData?.find(
|
|
(d) =>
|
|
d.symbol.toLowerCase() === symbol.toLowerCase() ||
|
|
(symbol === 'ETH (Portal)' && d.symbol === 'ETH'),
|
|
)
|
|
|
|
const interestAmount = hasInterestEarned
|
|
? hasInterestEarned.borrow_interest * -1 +
|
|
hasInterestEarned.deposit_interest
|
|
: 0
|
|
|
|
const interestValue = hasInterestEarned
|
|
? hasInterestEarned.borrow_interest_usd * -1 +
|
|
hasInterestEarned.deposit_interest_usd
|
|
: 0
|
|
|
|
return (
|
|
<>
|
|
<div className="h-full w-full bg-th-bkg-2 p-4 md:p-6">
|
|
<h2 className="mb-4 text-lg">Your {bank?.name}</h2>
|
|
<div className="border-b border-th-bkg-4">
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('balance')}</p>
|
|
<p className="font-mono text-th-fgd-2">
|
|
{mangoAccount ? (
|
|
<FormatNumericValue
|
|
value={mangoAccount.getTokenBalanceUi(bank)}
|
|
decimals={bank.mintDecimals}
|
|
/>
|
|
) : (
|
|
0
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('collateral-value')}</p>
|
|
<p className="font-mono text-th-fgd-2">
|
|
{mangoAccount ? formatCurrencyValue(collateralValue) : '$0.00'}
|
|
</p>
|
|
</div>
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('trade:in-orders')}</p>
|
|
<p className="font-mono text-th-fgd-2">
|
|
{inOrders ? (
|
|
<FormatNumericValue
|
|
value={inOrders}
|
|
decimals={bank.mintDecimals}
|
|
/>
|
|
) : (
|
|
0
|
|
)}
|
|
</p>
|
|
</div>
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('trade:unsettled')}</p>
|
|
{unsettled ? (
|
|
<div className="flex space-x-2">
|
|
<p className="font-mono text-th-fgd-2">
|
|
<FormatNumericValue
|
|
value={unsettled}
|
|
decimals={bank.mintDecimals}
|
|
/>
|
|
</p>
|
|
<LinkButton onClick={() => setShowSettleModal(true)}>
|
|
{t('trade:settle')}
|
|
</LinkButton>
|
|
</div>
|
|
) : (
|
|
<p className="font-mono text-th-fgd-2">0</p>
|
|
)}
|
|
</div>
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('interest-earned')}</p>
|
|
<div>
|
|
<p className="text-right font-mono text-th-fgd-2">
|
|
{interestAmount ? (
|
|
<FormatNumericValue
|
|
value={interestAmount}
|
|
decimals={bank.mintDecimals}
|
|
/>
|
|
) : (
|
|
0
|
|
)}
|
|
</p>
|
|
<p className="text-right font-mono text-xs text-th-fgd-3">
|
|
$
|
|
{interestValue ? (
|
|
<FormatNumericValue value={interestValue} decimals={2} />
|
|
) : (
|
|
0
|
|
)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-between border-t border-th-bkg-4 py-3">
|
|
<p>{t('rates')}</p>
|
|
<div className="flex justify-end space-x-1.5 font-mono">
|
|
<TableRatesDisplay
|
|
borrowRate={borrowRate}
|
|
depositRate={depositRate}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex space-x-4 pt-8">
|
|
<Button
|
|
className="flex-1"
|
|
secondary
|
|
disabled={!mangoAccount}
|
|
onClick={() => setShowDepositModal('deposit')}
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<ArrowDownTrayIcon className="h-5 w-5" />
|
|
<span>{t('deposit')}</span>
|
|
</div>
|
|
</Button>
|
|
<Button
|
|
className="flex-1"
|
|
secondary
|
|
disabled={!mangoAccount}
|
|
onClick={() => setShowDepositModal('withdraw')}
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<ArrowUpTrayIcon className="h-5 w-5" />
|
|
<span>{t('withdraw')}</span>
|
|
</div>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
{showDepositModal ? (
|
|
<DepositWithdrawModal
|
|
action={showDepositModal}
|
|
isOpen={!!showDepositModal}
|
|
onClose={() => setShowDepositModal('')}
|
|
token={bank?.name}
|
|
/>
|
|
) : null}
|
|
{showSettleModal ? (
|
|
<UnsettledModal
|
|
isOpen={showSettleModal}
|
|
onClose={() => setShowSettleModal(false)}
|
|
/>
|
|
) : null}
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default ActionPanel
|
|
|
|
const UnsettledModal = ({ isOpen, onClose }: ModalProps) => {
|
|
const { t } = useTranslation('trade')
|
|
return (
|
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
<h2 className="mb-4 text-center md:mb-0">{t('unsettled-balances')}</h2>
|
|
<div className="border-t border-th-bkg-3 md:border-t-0">
|
|
<UnsettledTrades />
|
|
</div>
|
|
</Modal>
|
|
)
|
|
}
|