import { PerpMarket, PerpOrder, Serum3Market, Serum3Side, } from '@blockworks-foundation/mango-v4' import { IconButton } from '@components/shared/Button' import Loading from '@components/shared/Loading' import SideBadge from '@components/shared/SideBadge' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import Tooltip from '@components/shared/Tooltip' import { LinkIcon, NoSymbolIcon, TrashIcon } from '@heroicons/react/20/solid' import { Order } from '@project-serum/serum/lib/market' import { useWallet } from '@solana/wallet-adapter-react' import { PublicKey } from '@solana/web3.js' import mangoStore from '@store/mangoStore' import { useViewport } from 'hooks/useViewport' import { useTranslation } from 'next-i18next' import { useCallback, useState } from 'react' import { notify } from 'utils/notifications' import { formatFixedDecimals, getDecimalCount } from 'utils/numbers' import { breakpoints } from 'utils/theme' import TableMarketName from './TableMarketName' const OpenOrders = () => { const { t } = useTranslation(['common', 'trade']) const { connected } = useWallet() const openOrders = mangoStore((s) => s.mangoAccount.openOrders) const [cancelId, setCancelId] = useState('') const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const handleCancelSerumOrder = useCallback( async (o: Order) => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const selectedMarket = mangoStore.getState().selectedMarket.current const actions = mangoStore.getState().actions if (!group || !mangoAccount) return setCancelId(o.orderId.toString()) try { if (selectedMarket instanceof Serum3Market) { const tx = await client.serum3CancelOrder( group, mangoAccount, selectedMarket!.serumMarketExternal, o.side === 'buy' ? Serum3Side.bid : Serum3Side.ask, o.orderId ) actions.fetchOpenOrders() notify({ type: 'success', title: 'Transaction successful', txid: tx, }) } } catch (e: any) { console.error('Error canceling', e) notify({ title: t('trade:cancel-order-error'), description: e.message, txid: e.txid, type: 'error', }) } finally { setCancelId('') } }, [t] ) const handleCancelPerpOrder = useCallback( async (o: PerpOrder) => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const selectedMarket = mangoStore.getState().selectedMarket.current const actions = mangoStore.getState().actions if (!group || !mangoAccount) return setCancelId(o.orderId.toString()) try { if (selectedMarket instanceof PerpMarket) { const tx = await client.perpCancelOrder( group, mangoAccount, o.perpMarketIndex, o.orderId ) actions.fetchOpenOrders() notify({ type: 'success', title: 'Transaction successful', txid: tx, }) } } catch (e: any) { console.error('Error canceling', e) notify({ title: t('trade:cancel-order-error'), description: e.message, txid: e.txid, type: 'error', }) } finally { setCancelId('') } }, [t] ) return connected ? ( Object.values(openOrders).flat().length ? ( showTableView ? ( {Object.entries(openOrders) .map(([marketPk, orders]) => { return orders.map((o) => { const group = mangoStore.getState().group! let market: PerpMarket | Serum3Market let tickSize: number let minOrderSize: number let quoteSymbol if (o instanceof PerpOrder) { market = group.getPerpMarketByMarketIndex(o.perpMarketIndex) quoteSymbol = group.getFirstBankByTokenIndex( market.settleTokenIndex ).name tickSize = market.tickSize minOrderSize = market.minOrderSize } else { market = group.getSerum3MarketByExternalMarket( new PublicKey(marketPk) ) quoteSymbol = group.getFirstBankByTokenIndex( market!.quoteTokenIndex ).name const serumMarket = group.getSerum3ExternalMarket( market.serumMarketExternal ) tickSize = serumMarket.tickSize minOrderSize = serumMarket.minOrderSize } return ( ) }) }) .flat()}
{t('market')} {t('trade:side')} {t('trade:size')} {t('price')} {t('value')}
{o.size.toLocaleString(undefined, { maximumFractionDigits: getDecimalCount(minOrderSize), })} {o.price.toLocaleString(undefined, { minimumFractionDigits: getDecimalCount(tickSize), maximumFractionDigits: getDecimalCount(tickSize), })}{' '} {quoteSymbol} {formatFixedDecimals(o.size * o.price, true)}
o instanceof PerpOrder ? handleCancelPerpOrder(o) : handleCancelSerumOrder(o) } size="small" > {cancelId === o.orderId.toString() ? ( ) : ( )}
) : (
{Object.entries(openOrders).map(([marketPk, orders]) => { return orders.map((o) => { const group = mangoStore.getState().group! let market: PerpMarket | Serum3Market let tickSize: number let minOrderSize: number let quoteSymbol: string let baseSymbol: string if (o instanceof PerpOrder) { market = group.getPerpMarketByMarketIndex(o.perpMarketIndex) baseSymbol = market.name.split('-')[0] quoteSymbol = group.getFirstBankByTokenIndex( market.settleTokenIndex ).name tickSize = market.tickSize minOrderSize = market.minOrderSize } else { market = group.getSerum3MarketByExternalMarket( new PublicKey(marketPk) ) baseSymbol = market.name.split('/')[0] quoteSymbol = group.getFirstBankByTokenIndex( market!.quoteTokenIndex ).name const serumMarket = group.getSerum3ExternalMarket( market.serumMarketExternal ) tickSize = serumMarket.tickSize minOrderSize = serumMarket.minOrderSize } return (

{o.size.toLocaleString(undefined, { maximumFractionDigits: getDecimalCount(minOrderSize), })} {' '} {baseSymbol}

{o.price.toLocaleString(undefined, { minimumFractionDigits: getDecimalCount(tickSize), maximumFractionDigits: getDecimalCount(tickSize), })} {' '} {quoteSymbol}

o instanceof PerpOrder ? handleCancelPerpOrder(o) : handleCancelSerumOrder(o) } > {cancelId === o.orderId.toString() ? ( ) : ( )}
) }) })}
) ) : (

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

) ) : (

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

) } export default OpenOrders