import { Serum3Market } from '@blockworks-foundation/mango-v4' import useJupiterMints from 'hooks/useJupiterMints' import { ChevronDownIcon, NoSymbolIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' 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 { useCallback, useMemo } from 'react' import { floorToDecimal, formatNumericValue, getDecimalCount, } from 'utils/numbers' import { breakpoints } from 'utils/theme' import { calculateLimitPriceForMarketOrder } from 'utils/tradeForm' import { LinkButton } from './Button' import { Table, Td, Th, TrBody, TrHead } from './TableElements' import useSelectedMarket from 'hooks/useSelectedMarket' import ConnectEmptyState from './ConnectEmptyState' import { useWallet } from '@solana/wallet-adapter-react' import FormatNumericValue from './FormatNumericValue' import BankAmountWithValue from './BankAmountWithValue' import useBanksWithBalances, { BankWithBalance, } from 'hooks/useBanksWithBalances' import useUnownedAccount from 'hooks/useUnownedAccount' import { Disclosure, Transition } from '@headlessui/react' const BalancesTable = () => { const { t } = useTranslation(['common', 'trade']) const { mangoAccount, mangoAccountAddress } = useMangoAccount() const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances) const { mangoTokens } = useJupiterMints() const { width } = useViewport() const { connected } = useWallet() const showTableView = width ? width > breakpoints.md : false const banks = useBanksWithBalances('balance') const filteredBanks = useMemo(() => { if (banks.length) { return banks.filter((b) => { return ( Math.abs(floorToDecimal(b.balance, b.bank.mintDecimals).toNumber()) > 0 || spotBalances[b.bank.mint.toString()]?.unsettled > 0 || spotBalances[b.bank.mint.toString()]?.inOrders > 0 ) }) } return [] }, [banks]) return filteredBanks.length ? ( showTableView ? ( {filteredBanks.map((b) => { const bank = b.bank 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}

) : (
{filteredBanks.map((b, i) => { const bank = b.bank let logoURI: string | undefined 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 ( {({ open }) => ( <>
{logoURI ? ( ) : ( )}

{bank.name}

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

{t('trade:unsettled')}

)}
) })}
) ) : mangoAccountAddress || connected ? (

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

) : (
) } export default BalancesTable const Balance = ({ bank }: { bank: BankWithBalance }) => { const { selectedMarket } = useSelectedMarket() const { asPath } = useRouter() const { isUnownedAccount } = useUnownedAccount() const tokenBank = bank.bank const handleTradeFormBalanceClick = useCallback( (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 = calculateLimitPriceForMarketOrder(orderbook, balance, side) } else { price = Number(tradeForm.price) } let minOrderDecimals: number let tickDecimals: number if (selectedMarket instanceof Serum3Market) { const market = group.getSerum3ExternalMarket( selectedMarket.serumMarketExternal ) minOrderDecimals = getDecimalCount(market.minOrderSize) tickDecimals = getDecimalCount(market.tickSize) } else { minOrderDecimals = getDecimalCount(selectedMarket.minOrderSize) tickDecimals = getDecimalCount(selectedMarket.tickSize) } if (type === 'quote') { const floorBalance = floorToDecimal(balance, tickDecimals).toNumber() const baseSize = floorToDecimal( floorBalance / price, minOrderDecimals ).toNumber() const quoteSize = floorToDecimal(baseSize * price, tickDecimals) set((s) => { s.tradeForm.baseSize = baseSize.toString() s.tradeForm.quoteSize = quoteSize.toString() }) } else { const baseSize = floorToDecimal(balance, minOrderDecimals).toNumber() const quoteSize = floorToDecimal(baseSize * price, tickDecimals) set((s) => { s.tradeForm.baseSize = baseSize.toString() s.tradeForm.quoteSize = quoteSize.toString() }) } }, [selectedMarket] ) const handleSwapFormBalanceClick = useCallback( (balance: number) => { const set = mangoStore.getState().set if (balance >= 0) { set((s) => { s.swap.inputBank = tokenBank s.swap.amountIn = balance.toString() s.swap.amountOut = '' s.swap.swapMode = 'ExactIn' }) } else { set((s) => { s.swap.outputBank = tokenBank s.swap.amountIn = '' s.swap.amountOut = Math.abs(balance).toString() s.swap.swapMode = 'ExactOut' }) } }, [bank] ) const balance = bank.balance const isBaseOrQuote = useMemo(() => { if (selectedMarket instanceof Serum3Market) { if (tokenBank.tokenIndex === selectedMarket.baseTokenIndex) { return 'base' } else if (tokenBank.tokenIndex === selectedMarket.quoteTokenIndex) { return 'quote' } else return '' } }, [tokenBank, selectedMarket]) if (!balance) return

0

return (

{!isUnownedAccount ? ( asPath.includes('/trade') && isBaseOrQuote ? ( handleTradeFormBalanceClick(Math.abs(balance), isBaseOrQuote) } > ) : asPath.includes('/swap') ? ( handleSwapFormBalanceClick( Number(formatNumericValue(balance, tokenBank.mintDecimals)) ) } > ) : ( ) ) : ( )}

) }