import { useCallback } from 'react' import { useBalances } from '../hooks/useBalances' import useMangoStore from '../stores/useMangoStore' import Button, { LinkButton } from '../components/Button' import { notify } from '../utils/notifications' import { ArrowSmDownIcon, ExclamationIcon } from '@heroicons/react/outline' import { Market } from '@project-serum/serum' import { getMarketIndexBySymbol, getTokenBySymbol, } from '@blockworks-foundation/mango-client' import { useState } from 'react' import Loading from './Loading' import { useViewport } from '../hooks/useViewport' import { breakpoints } from './TradePageGrid' import { floorToDecimal, formatUsdValue } from '../utils' import { Table, Td, Th, TrBody, TrHead } from './TableElements' import { useSortableData } from '../hooks/useSortableData' import DepositModal from './DepositModal' import WithdrawModal from './WithdrawModal' import { ExpandableRow } from './TableElements' import MobileTableHeader from './mobile/MobileTableHeader' import { useTranslation } from 'next-i18next' import { TransactionSignature } from '@solana/web3.js' const BalancesTable = ({ showZeroBalances = false, showDepositWithdraw = false, }) => { const { t } = useTranslation('common') const [showDepositModal, setShowDepositModal] = useState(false) const [showWithdrawModal, setShowWithdrawModal] = useState(false) const [actionSymbol, setActionSymbol] = useState('') const balances = useBalances() const { items, requestSort, sortConfig } = useSortableData( balances .filter( (bal) => showZeroBalances || +bal.deposits > 0 || +bal.borrows > 0 || bal.orders > 0 || bal.unsettled > 0 ) .sort((a, b) => Math.abs(+b.value) - Math.abs(+a.value)) ) const actions = useMangoStore((s) => s.actions) const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current) const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config) const mangoClient = useMangoStore((s) => s.connection.client) const selectedMarket = useMangoStore((s) => s.selectedMarket.current) const marketConfig = useMangoStore((s) => s.selectedMarket.config) const setMangoStore = useMangoStore((s) => s.set) const price = useMangoStore((s) => s.tradeForm.price) const mangoGroupCache = useMangoStore((s) => s.selectedMangoGroup.cache) const { width } = useViewport() const [submitting, setSubmitting] = useState(false) const isMobile = width ? width < breakpoints.md : false const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const wallet = useMangoStore((s) => s.wallet.current) const canWithdraw = mangoAccount?.owner.equals(wallet.publicKey) const handleSizeClick = (size, symbol) => { const step = selectedMarket.minOrderSize const marketIndex = getMarketIndexBySymbol( mangoGroupConfig, marketConfig.baseSymbol ) const priceOrDefault = price ? price : mangoGroup.getPrice(marketIndex, mangoGroupCache).toNumber() if (symbol === 'USDC') { const baseSize = Math.floor(size / priceOrDefault / step) * step setMangoStore((state) => { state.tradeForm.baseSize = baseSize state.tradeForm.quoteSize = baseSize * priceOrDefault state.tradeForm.side = 'buy' }) } else { const roundedSize = Math.round(size / step) * step const quoteSize = roundedSize * priceOrDefault setMangoStore((state) => { state.tradeForm.baseSize = roundedSize state.tradeForm.quoteSize = quoteSize state.tradeForm.side = 'sell' }) } } const handleOpenDepositModal = useCallback((symbol) => { setActionSymbol(symbol) setShowDepositModal(true) }, []) const handleOpenWithdrawModal = useCallback((symbol) => { setActionSymbol(symbol) setShowWithdrawModal(true) }, []) async function handleSettleAll() { const markets = useMangoStore.getState().selectedMangoGroup.markets try { setSubmitting(true) const spotMarkets = Object.values(markets).filter( (mkt) => mkt instanceof Market ) as Market[] const txids: TransactionSignature[] = await mangoClient.settleAll( mangoGroup, mangoAccount, spotMarkets, wallet ) for (const txid of txids) { notify({ title: t('settle-success'), txid }) } } catch (e) { console.warn('Error settling all:', e) if (e.message === 'No unsettled funds') { notify({ title: t('no-unsettled'), type: 'error', }) } else { notify({ title: t('settle-error'), description: e.message, txid: e.txid, type: 'error', }) } } finally { actions.reloadOrders() // actions.reloadMangoAccount() setSubmitting(false) } } const unsettledBalances = balances.filter((bal) => bal.unsettled > 0) return (
{unsettledBalances.length > 0 ? (

{t('unsettled-balances')}

{unsettledBalances.map((bal) => { const tokenConfig = getTokenBySymbol(mangoGroupConfig, bal.symbol) return (
{bal.symbol}
{`${floorToDecimal(bal.unsettled, tokenConfig.decimals)} ${ bal.symbol }`}
) })}
) : null}
{items.length > 0 ? ( !isMobile ? ( {items.map((balance, index) => ( {showDepositWithdraw ? ( ) : null} ))} {showDepositModal && ( setShowDepositModal(false)} tokenSymbol={actionSymbol} // repayAmount={ // balance.borrows.toNumber() > 0 // ? balance.borrows.toFixed() // : '' // } /> )} {showWithdrawModal && ( setShowWithdrawModal(false)} tokenSymbol={actionSymbol} /> )}
requestSort('symbol')} > {t('asset')} requestSort('deposits')} > {t('deposits')} requestSort('borrows')} > {t('borrows')} requestSort('orders')} > {t('in-orders')} requestSort('unsettled')} > {t('unsettled')} requestSort('net')} > {t('net-balance')} requestSort('value')} > {t('value')} requestSort('depositRate')} > {t('deposit-rate')} requestSort('borrowRate')} > {t('borrow-rate')}
{balance.symbol}
{balance.deposits.toFixed()} {balance.borrows.toFixed()} {balance.orders} {balance.unsettled} {marketConfig.kind === 'spot' && marketConfig.name.includes(balance.symbol) && selectedMarket ? ( 0 ? 'cursor-pointer underline hover:no-underline' : '' } onClick={() => handleSizeClick(balance.net, balance.symbol) } > {balance.net.toFixed()} ) : ( balance.net.toFixed() )} {formatUsdValue(balance.value.toNumber())} {balance.depositRate.toFixed(2)}% {balance.borrowRate.toFixed(2)}%
) : ( <> {items.map((balance, index) => (
{balance.symbol}
{balance.net.toFixed()}
} key={`${balance.symbol}${index}`} index={index} panelTemplate={ <>
{t('deposits')}
{balance.deposits.toFixed()}
{t('borrows')}
{balance.borrows.toFixed()}
{t('in-orders')}
{balance.orders.toFixed()}
{t('unsettled')}
{balance.unsettled.toFixed()}
{t('value')}
{formatUsdValue(balance.value.toNumber())}
{t('rates')}
{balance.depositRate.toFixed(2)}% / {balance.borrowRate.toFixed(2)}%
{showDepositModal && ( setShowDepositModal(false)} tokenSymbol={actionSymbol} repayAmount={ balance.borrows.toNumber() > 0 ? balance.borrows.toFixed() : '' } /> )} {showWithdrawModal && ( setShowWithdrawModal(false)} tokenSymbol={actionSymbol} /> )} } /> ))} ) ) : (
{t('no-balances')}
)}
) } export default BalancesTable