/* eslint-disable @typescript-eslint/no-explicit-any */ import mangoStore from '@store/mangoStore' import { useTranslation } from 'next-i18next' import { useCallback, useState } from 'react' import { PublicKey } from '@solana/web3.js' import { IconButton } from '@components/shared/Button' import { notify } from 'utils/notifications' import { CheckIcon, NoSymbolIcon } from '@heroicons/react/20/solid' import Tooltip from '@components/shared/Tooltip' import Loading from '@components/shared/Loading' import { useViewport } from 'hooks/useViewport' import { breakpoints } from 'utils/theme' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import useMangoGroup from 'hooks/useMangoGroup' import { PerpMarket, PerpPosition } from '@blockworks-foundation/mango-v4' import TableMarketName from './TableMarketName' import useMangoAccount from 'hooks/useMangoAccount' import { useWallet } from '@solana/wallet-adapter-react' import ConnectEmptyState from '@components/shared/ConnectEmptyState' import FormatNumericValue from '@components/shared/FormatNumericValue' import useUnownedAccount from 'hooks/useUnownedAccount' import { isMangoError } from 'types' const UnsettledTrades = ({ unsettledSpotBalances, unsettledPerpPositions, }: { unsettledSpotBalances: any unsettledPerpPositions: PerpPosition[] }) => { const { t } = useTranslation(['common', 'trade']) const { group } = useMangoGroup() const [settleMktAddress, setSettleMktAddress] = useState('') const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const { mangoAccountAddress } = useMangoAccount() const { connected } = useWallet() const { isUnownedAccount } = useUnownedAccount() const handleSettleSerumFunds = useCallback(async (mktAddress: string) => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const actions = mangoStore.getState().actions if (!group || !mangoAccount) return setSettleMktAddress(mktAddress) try { const txid = await client.serum3SettleFunds( group, mangoAccount, new PublicKey(mktAddress) ) actions.fetchOpenOrders() notify({ type: 'success', title: 'Successfully settled funds', txid, }) } catch (e) { if (isMangoError(e)) { notify({ type: 'error', title: t('trade:settle-funds-error'), description: e?.message, txid: e?.txid, }) } console.error('Settle funds error:', e) } finally { setSettleMktAddress('') } }, []) const handleSettlePerpFunds = useCallback(async (market: PerpMarket) => { const client = mangoStore.getState().client const group = mangoStore.getState().group const mangoAccount = mangoStore.getState().mangoAccount.current const actions = mangoStore.getState().actions if (!group || !mangoAccount) return setSettleMktAddress(market.publicKey.toString()) try { const perpPosition = mangoAccount.getPerpPosition(market.perpMarketIndex) const mangoAccountPnl = perpPosition?.getEquityUi(market) if (mangoAccountPnl === undefined) throw new Error('Unable to get account P&L') console.log('mangoAccountPnl', mangoAccountPnl) const settleCandidates = await market.getSettlePnlCandidates( client, group, mangoAccountPnl < 0 ? 'positive' : 'negative', 2 ) console.log('settleCandidates', settleCandidates) const profitableAccount = mangoAccountPnl < 0 ? settleCandidates[0].account : mangoAccount const unprofitableAccount = mangoAccountPnl > 0 ? settleCandidates[0].account : mangoAccount const txid = await client.perpSettlePnlAndFees( group, profitableAccount, unprofitableAccount, mangoAccount, mangoAccount, market.perpMarketIndex ) actions.reloadMangoAccount() notify({ type: 'success', title: 'Successfully settled P&L', txid, }) } catch (e) { if (isMangoError(e)) { notify({ type: 'error', title: 'Settle P&L error', description: e?.message, txid: e?.txid, }) } console.error('Settle P&L error:', e) } finally { setSettleMktAddress('') } }, []) if (!group) return null return mangoAccountAddress && Object.values(unsettledSpotBalances).flat().concat(unsettledPerpPositions) .length ? ( showTableView ? ( {!isUnownedAccount ? ( {Object.entries(unsettledSpotBalances).map(([mktAddress]) => { const market = group.getSerum3MarketByExternalMarket( new PublicKey(mktAddress) ) const base = market?.name.split('/')[0] const quote = market?.name.split('/')[1] return ( {!isUnownedAccount ? ( ) : null} ) })} {unsettledPerpPositions.map((position) => { const market = group.getPerpMarketByMarketIndex( position.marketIndex ) return ( {!isUnownedAccount ? ( ) : null} ) })}
{t('market')} {t('trade:amount')} ) : null}
{unsettledSpotBalances[mktAddress].base ? (
{' '} {base}
) : null} {unsettledSpotBalances[mktAddress].quote ? (
{' '} {quote}
) : null}
handleSettleSerumFunds(mktAddress)} size="small" > {settleMktAddress === mktAddress ? ( ) : ( )}
{' '} USDC
handleSettlePerpFunds(market)} size="small" > {settleMktAddress === market.publicKey.toString() ? ( ) : ( )}
) : (
{unsettledPerpPositions.map((position) => { const market = group.getPerpMarketByMarketIndex(position.marketIndex) return (
{' '} USDC
{!isUnownedAccount ? ( handleSettlePerpFunds(market)} size="small" > {settleMktAddress === market.publicKey.toString() ? ( ) : ( )} ) : null}
) })} {Object.entries(unsettledSpotBalances).map(([mktAddress]) => { const market = group.getSerum3MarketByExternalMarket( new PublicKey(mktAddress) ) const base = market?.name.split('/')[0] const quote = market?.name.split('/')[1] return (
{unsettledSpotBalances[mktAddress].base ? ( {' '} {base} ) : null} {unsettledSpotBalances[mktAddress].quote ? ( {' '} {quote} ) : null} {!isUnownedAccount ? ( handleSettleSerumFunds(mktAddress)} size="small" > {settleMktAddress === mktAddress ? ( ) : ( )} ) : null}
) })}
) ) : mangoAccountAddress || connected ? (

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

) : (
) } export default UnsettledTrades