import { Bank, Serum3Market } from '@blockworks-foundation/mango-v4' import useJupiterMints from 'hooks/useJupiterMints' import { QuestionMarkCircleIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' import Decimal from 'decimal.js' import useMangoAccount from 'hooks/useMangoAccount' import { useViewport } from 'hooks/useViewport' import { useTranslation } from 'next-i18next' import Image from 'next/legacy/image' import { useRouter } from 'next/router' import { useMemo } from 'react' import { floorToDecimal, formatDecimal, formatFixedDecimals, getDecimalCount, trimDecimals, } from 'utils/numbers' import { breakpoints } from 'utils/theme' import { calculateMarketPrice } from 'utils/tradeForm' import { LinkButton } from './Button' import { Table, Td, Th, TrBody, TrHead } from './TableElements' import useSelectedMarket from 'hooks/useSelectedMarket' import useMangoGroup from 'hooks/useMangoGroup' const BalancesTable = () => { const { t } = useTranslation(['common', 'trade']) const { mangoAccount } = useMangoAccount() const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances) const { group } = useMangoGroup() const { mangoTokens } = useJupiterMints() const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const banks = useMemo(() => { if (!group) return [] const rawBanks = Array.from(group?.banksMapByName, ([key, value]) => ({ key, value, balance: mangoAccount?.getTokenBalanceUi(value[0]), })) const sortedBanks = mangoAccount ? rawBanks .sort( (a, b) => Math.abs(b.balance! * b.value[0].uiPrice) - Math.abs(a.balance! * a.value[0].uiPrice) ) .filter( (c) => Math.abs( floorToDecimal(c.balance!, c.value[0].mintDecimals).toNumber() ) > 0 ) : rawBanks return sortedBanks }, [group, mangoAccount]) return banks?.length ? ( showTableView ? ( {banks.map(({ key, value }) => { const bank = value[0] let logoURI if (mangoTokens.length) { logoURI = mangoTokens.find( (t) => t.address === bank.mint.toString() )?.logoURI } const inOrders = spotBalances[bank.mint.toString()]?.inOrders || 0 const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0 return ( ) })}
{t('token')} {t('balance')} {t('trade:in-orders')} {t('trade:unsettled')}
{logoURI ? ( ) : ( )}
{bank.name}

{mangoAccount ? `${formatFixedDecimals( mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice, true )}` : '$0.00'}

{inOrders}

{formatFixedDecimals(inOrders * bank.uiPrice, true)}

{unsettled ? unsettled.toFixed(bank.mintDecimals) : 0}

{formatFixedDecimals(unsettled * bank.uiPrice, true)}

) : ( <> {banks.map(({ key, value }) => { const bank = value[0] let logoURI if (mangoTokens.length) { logoURI = mangoTokens.find( (t) => t.address === bank.mint.toString() )?.logoURI } const inOrders = spotBalances[bank.mint.toString()]?.inOrders || 0 const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0 return (
{logoURI ? ( ) : ( )}
{bank.name}
( {mangoAccount ? `${formatFixedDecimals( mangoAccount.getTokenBalanceUi(bank) * bank.uiPrice, true )}` : '$0.00'} )

{t('trade:in-orders')}:{' '} {inOrders}

{t('trade:unsettled')}:{' '} {unsettled ? unsettled.toFixed(bank.mintDecimals) : 0}

) })} ) ) : (

{t('trade:no-balances')}

) } export default BalancesTable const Balance = ({ bank }: { bank: Bank }) => { const { mangoAccount } = useMangoAccount() const { selectedMarket } = useSelectedMarket() const { asPath } = useRouter() const handleBalanceClick = (balance: number, type: 'base' | 'quote') => { const set = mangoStore.getState().set const group = mangoStore.getState().group const tradeForm = mangoStore.getState().tradeForm if (!group || !selectedMarket) return let price: number if (tradeForm.tradeType === 'Market') { const orderbook = mangoStore.getState().selectedMarket.orderbook const side = (balance > 0 && type === 'quote') || (balance < 0 && type === 'base') ? 'buy' : 'sell' price = calculateMarketPrice(orderbook, balance, side) } else { price = new Decimal(tradeForm.price).toNumber() } let minOrderDecimals: number let tickSize: number if (selectedMarket instanceof Serum3Market) { const market = group.getSerum3ExternalMarket( selectedMarket.serumMarketExternal ) minOrderDecimals = getDecimalCount(market.minOrderSize) tickSize = getDecimalCount(market.tickSize) } else { minOrderDecimals = getDecimalCount(selectedMarket.minOrderSize) tickSize = getDecimalCount(selectedMarket.tickSize) } if (type === 'quote') { const trimmedBalance = trimDecimals(balance, tickSize) const baseSize = trimDecimals(trimmedBalance / price, minOrderDecimals) const quoteSize = trimDecimals(baseSize * price, tickSize) set((s) => { s.tradeForm.baseSize = baseSize.toString() s.tradeForm.quoteSize = quoteSize.toString() }) } else { const baseSize = trimDecimals(balance, minOrderDecimals) const quoteSize = trimDecimals(baseSize * price, tickSize) set((s) => { s.tradeForm.baseSize = baseSize.toString() s.tradeForm.quoteSize = quoteSize.toString() }) } } const balance = useMemo(() => { return mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0 }, [mangoAccount]) const isBaseOrQuote = useMemo(() => { if (selectedMarket instanceof Serum3Market && asPath.includes('/trade')) { if (bank.tokenIndex === selectedMarket.baseTokenIndex) { return 'base' } else if (bank.tokenIndex === selectedMarket.quoteTokenIndex) { return 'quote' } else return '' } }, [bank, selectedMarket]) return (

{balance ? ( isBaseOrQuote ? ( handleBalanceClick( parseFloat(formatDecimal(balance, bank.mintDecimals)), isBaseOrQuote ) } > {formatDecimal(balance, bank.mintDecimals)} ) : ( formatDecimal(balance, bank.mintDecimals) ) ) : ( 0 )}

) }