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 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,
formatDecimal,
formatFixedDecimals,
getDecimalCount,
trimDecimals,
} 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 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 ? (
{t('token')} |
{t('balance')} |
{t('trade:in-orders')} |
{t('trade:unsettled')}
|
{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'}
|
{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}
)
})}
>
)
) : (
)
}
export default BalancesTable
const Balance = ({ bank }: { bank: Bank }) => {
const { mangoAccount } = useMangoAccount()
const { selectedMarket } = useSelectedMarket()
const { asPath } = useRouter()
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 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()
})
}
},
[selectedMarket]
)
const handleSwapFormBalanceClick = useCallback((balance: number) => {
const set = mangoStore.getState().set
if (balance >= 0) {
set((s) => {
s.swap.inputBank = bank
s.swap.amountIn = balance.toString()
s.swap.swapMode = 'ExactIn'
})
} else {
console.log('else')
set((s) => {
s.swap.outputBank = bank
s.swap.amountOut = Math.abs(balance).toString()
s.swap.swapMode = 'ExactOut'
})
}
}, [])
const balance = useMemo(() => {
return mangoAccount ? mangoAccount.getTokenBalanceUi(bank) : 0
}, [bank, mangoAccount])
const isBaseOrQuote = useMemo(() => {
if (
selectedMarket instanceof Serum3Market &&
(asPath.includes('/trade') || asPath.includes('/swap'))
) {
if (bank.tokenIndex === selectedMarket.baseTokenIndex) {
return 'base'
} else if (bank.tokenIndex === selectedMarket.quoteTokenIndex) {
return 'quote'
} else return ''
}
}, [bank, selectedMarket])
const handleClick = (balance: number, type: 'base' | 'quote') => {
if (asPath.includes('/trade')) {
handleTradeFormBalanceClick(
parseFloat(formatDecimal(balance, bank.mintDecimals)),
type
)
} else {
handleSwapFormBalanceClick(
parseFloat(formatDecimal(balance, bank.mintDecimals))
)
}
}
return (
{balance ? (
isBaseOrQuote ? (
handleClick(balance, isBaseOrQuote)}
>
{formatDecimal(balance, bank.mintDecimals)}
) : (
formatDecimal(balance, bank.mintDecimals)
)
) : (
0
)}
)
}