import { useCallback, useMemo, useState } from 'react' import useMangoStore from '../stores/useMangoStore' import Button from '../components/Button' import { notify } from '../utils/notifications' import { ExclamationIcon, // InformationCircleIcon } from '@heroicons/react/solid' import { Market } from '@project-serum/serum' import { // getMarketIndexBySymbol, getTokenBySymbol, // ZERO_I80F48, } from '@blockworks-foundation/mango-client' import Loading from './Loading' import { useViewport } from '../hooks/useViewport' import { breakpoints } from './TradePageGrid' import { floorToDecimal, formatUsdValue, getPrecisionDigits, // usdFormatter, } from '../utils' import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements' import DepositModal from './DepositModal' import WithdrawModal from './WithdrawModal' import MobileTableHeader from './mobile/MobileTableHeader' import { useTranslation } from 'next-i18next' import { TransactionSignature } from '@solana/web3.js' import Link from 'next/link' import { useRouter } from 'next/router' import { useWallet } from '@solana/wallet-adapter-react' // import Tooltip from './Tooltip' const BalancesTable = ({ showZeroBalances = false, showDepositWithdraw = false, clickToPopulateTradeForm = false, }) => { const { t } = useTranslation('common') const [showDepositModal, setShowDepositModal] = useState(false) const [showWithdrawModal, setShowWithdrawModal] = useState(false) const [actionSymbol, setActionSymbol] = useState('') const spotBalances = useMangoStore((s) => s.selectedMangoAccount.spotBalances) const balances = useMemo(() => { return spotBalances?.length > 0 ? spotBalances .filter((bal) => { return ( showZeroBalances || (bal.deposits && +bal.deposits > 0) || (bal.borrows && +bal.borrows > 0) || (bal.orders && bal.orders > 0) || (bal.unsettled && bal.unsettled > 0) ) }) .sort((a, b) => { const aV = a.value ? Math.abs(+a.value) : 0 const bV = b.value ? Math.abs(+b.value) : 0 return bV - aV }) : [] }, [spotBalances]) const actions = useMangoStore((s) => s.actions) const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current) const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config) // const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache) 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, publicKey } = useWallet() const canWithdraw = publicKey ? mangoAccount?.owner.equals(publicKey) : true const { asPath } = useRouter() const handleSizeClick = (size, symbol) => { const minOrderSize = selectedMarket?.minOrderSize const sizePrecisionDigits = minOrderSize ? getPrecisionDigits(minOrderSize) : null const marketIndex = marketConfig.marketIndex const priceOrDefault = price ? price : mangoGroup && mangoGroupCache ? mangoGroup.getPriceUi(marketIndex, mangoGroupCache) : null if (!priceOrDefault || !sizePrecisionDigits || !minOrderSize) { return } let roundedSize, side if (symbol === 'USDC') { roundedSize = parseFloat( ( Math.abs(size) / priceOrDefault + (size < 0 ? minOrderSize / 2 : -minOrderSize / 2) ) // round up so neg USDC gets cleared .toFixed(sizePrecisionDigits) ) side = size > 0 ? 'buy' : 'sell' } else { roundedSize = parseFloat( ( Math.abs(size) + (size < 0 ? minOrderSize / 2 : -minOrderSize / 2) ).toFixed(sizePrecisionDigits) ) side = size > 0 ? 'sell' : 'buy' } const quoteSize = parseFloat((roundedSize * priceOrDefault).toFixed(2)) setMangoStore((state) => { state.tradeForm.baseSize = roundedSize state.tradeForm.quoteSize = quoteSize state.tradeForm.side = side }) } 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 const mangoClient = useMangoStore.getState().connection.client try { setSubmitting(true) const spotMarkets = Object.values(markets).filter( (mkt) => mkt instanceof Market ) as Market[] if (!mangoGroup || !mangoAccount || !wallet) { return } const txids: TransactionSignature[] | undefined = await mangoClient.settleAll( mangoGroup, mangoAccount, spotMarkets, wallet?.adapter ) if (txids) { for (const txid of txids) { notify({ title: t('settle-success'), txid }) } } else { notify({ title: t('settle-error'), type: 'error', }) } } 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 = spotBalances.filter( (bal) => bal.unsettled && bal.unsettled > 0 ) const trimDecimals = useCallback((num: string) => { if (parseFloat(num) === 0) { return '0' } // Trim the decimals depending on the length of the whole number const splitNum = num.split('.') if (splitNum.length > 1) { const wholeNum = splitNum[0] const decimals = splitNum[1] if (wholeNum.length > 8) { return `${wholeNum}.${decimals.substring(0, 2)}` } else if (wholeNum.length > 3) { return `${wholeNum}.${decimals.substring(0, 3)}` } } return num }, []) return (
{bal.symbol}
{bal.unsettled ? ({''} | {t('deposits')} | {t('borrows')} | {t('in-orders')} | {t('unsettled')} | {t('net-balance')} | {t('value')} | {/*
| */}
{t('deposit')} | {t('borrow')} (APR) |
{balance.symbol === 'USDC' ||
decodeURIComponent(asPath).includes(
`${balance.symbol}/USDC`
) ? (
{balance.symbol}
) : (
{balance.symbol}
)}
|
{trimDecimals( balance.deposits.toFormat(balance.decimals) )} | {trimDecimals( balance.borrows.toFormat(balance.decimals) )} | {balance.orders?.toLocaleString(undefined, { maximumFractionDigits: balance.decimals, })} | {balance.unsettled?.toLocaleString(undefined, { maximumFractionDigits: balance.decimals, })} | {marketConfig.kind === 'spot' && marketConfig.name.includes(balance.symbol) && selectedMarket && clickToPopulateTradeForm ? ( handleSizeClick(balance.net, balance.symbol) } > {trimDecimals( balance.net.toFormat(balance.decimals) )} ) : ( trimDecimals(balance.net.toFormat(balance.decimals)) )} | {formatUsdValue(balance.value.toNumber())} | {/*{liquidationPrice && liquidationPrice.gt(ZERO_I80F48) ? usdFormatter(liquidationPrice) : '–'} | */}{balance.depositRate.toFixed(2)}% | {balance.borrowRate.toFixed(2)}% | {showDepositWithdraw ? (
|
) : null}
---|