import { useCallback, useMemo, useState } from 'react' import { ElementTitle } from './styles' import useMangoStore from '../stores/useMangoStore' import { formatUsdValue } from '../utils/index' import Button, { LinkButton } from './Button' import Tooltip from './Tooltip' import PerpSideBadge from './PerpSideBadge' import { getMarketIndexBySymbol, MangoAccount, PerpAccount, PerpMarket, QUOTE_INDEX, } from '@blockworks-foundation/mango-client' import useTradeHistory from '../hooks/useTradeHistory' import { notify } from '../utils/notifications' import MarketCloseModal from './MarketCloseModal' import PnlText from './PnlText' import Loading from './Loading' import { useViewport } from '../hooks/useViewport' import { breakpoints } from './TradePageGrid' import { collectPerpPosition } from '../hooks/usePerpPositions' import { useTranslation } from 'next-i18next' import useMangoAccount from '../hooks/useMangoAccount' export const settlePnl = async ( perpMarket: PerpMarket, perpAccount: PerpAccount, t, mangoAccounts: MangoAccount[] | undefined ) => { const mangoAccount = useMangoStore.getState().selectedMangoAccount.current const mangoGroup = useMangoStore.getState().selectedMangoGroup.current const mangoCache = useMangoStore.getState().selectedMangoGroup.cache const wallet = useMangoStore.getState().wallet.current const actions = useMangoStore.getState().actions const marketIndex = mangoGroup.getPerpMarketIndex(perpMarket.publicKey) const mangoClient = useMangoStore.getState().connection.client try { const txid = await mangoClient.settlePnl( mangoGroup, mangoCache, mangoAccount, perpMarket, mangoGroup.rootBankAccounts[QUOTE_INDEX], mangoCache.priceCache[marketIndex].price, wallet, mangoAccounts ) actions.reloadMangoAccount() notify({ title: t('pnl-success'), description: '', txid, }) } catch (e) { console.log('Error settling PNL: ', `${e}`, `${perpAccount}`) notify({ title: t('pnl-error'), description: e.message, txid: e.txid, type: 'error', }) } } export default function MarketPosition() { const { t } = useTranslation('common') const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current) const mangoGroupConfig = useMangoStore((s) => s.selectedMangoGroup.config) const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache) const { mangoAccount, initialLoad } = useMangoAccount() const selectedMarket = useMangoStore((s) => s.selectedMarket.current) const marketConfig = useMangoStore((s) => s.selectedMarket.config) const connected = useMangoStore((s) => s.wallet.connected) const setMangoStore = useMangoStore((s) => s.set) const price = useMangoStore((s) => s.tradeForm.price) const baseSymbol = marketConfig.baseSymbol const marketName = marketConfig.name const tradeHistory = useTradeHistory() const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const [settling, setSettling] = useState(false) const { width } = useViewport() const isMobile = width ? width < breakpoints.sm : false const marketIndex = useMemo(() => { return getMarketIndexBySymbol(mangoGroupConfig, baseSymbol) }, [mangoGroupConfig, baseSymbol]) let perpAccount if (marketName.includes('PERP') && mangoAccount) { perpAccount = mangoAccount.perpAccounts[marketIndex] } const handleSizeClick = (size, side) => { const step = selectedMarket.minOrderSize const priceOrDefault = price ? price : mangoGroup.getPrice(marketIndex, mangoCache).toNumber() const roundedSize = Math.round(size / step) * step const quoteSize = roundedSize * priceOrDefault setMangoStore((state) => { state.tradeForm.baseSize = roundedSize state.tradeForm.quoteSize = quoteSize.toFixed(2) state.tradeForm.side = side === 'buy' ? 'sell' : 'buy' }) } const handleCloseWarning = useCallback(() => { setShowMarketCloseModal(false) }, []) const handleSettlePnl = (perpMarket, perpAccount) => { setSettling(true) settlePnl(perpMarket, perpAccount, t, undefined).then(() => { setSettling(false) }) } if (!mangoGroup || !selectedMarket || !(selectedMarket instanceof PerpMarket)) return null const { basePosition, avgEntryPrice, breakEvenPrice, notionalSize, unsettledPnl, } = collectPerpPosition( mangoAccount, mangoGroup, mangoCache, marketConfig, selectedMarket, tradeHistory ) function SettlePnlTooltip() { return (
{t('pnl-help')}{' '} {t('learn-more')}
) } return ( <>
{!isMobile ? ( {marketConfig.name} {t('position')} ) : null}
{t('side')}
{initialLoad ? ( ) : ( )}
{t('position-size')}
{initialLoad ? ( ) : basePosition ? ( handleSizeClick( Math.abs(basePosition), basePosition > 0 ? 'buy' : 'sell' ) } > {`${Math.abs(basePosition)} ${baseSymbol}`} ) : ( `0 ${baseSymbol}` )}
{t('notional-size')}
{initialLoad ? ( ) : notionalSize ? ( formatUsdValue(Math.abs(notionalSize)) ) : ( '$0' )}
{t('average-entry')}
{initialLoad ? ( ) : avgEntryPrice ? ( formatUsdValue(avgEntryPrice) ) : ( '$0' )}
{t('break-even')}
{initialLoad ? ( ) : breakEvenPrice ? ( formatUsdValue(breakEvenPrice) ) : ( '$0' )}
}> {t('unsettled-balance')}
{initialLoad ? : } {settling ? ( ) : ( handleSettlePnl(selectedMarket, perpAccount)} className="ml-2 text-th-primary text-xs disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:underline" disabled={unsettledPnl === 0} > {t('settle')} )}
{basePosition ? ( ) : null}
{showMarketCloseModal ? ( ) : null} ) } export const DataLoader = () => (
)