diff --git a/components/BalancesTable.tsx b/components/BalancesTable.tsx index e3383325..24060945 100644 --- a/components/BalancesTable.tsx +++ b/components/BalancesTable.tsx @@ -132,6 +132,7 @@ const BalancesTable = ({ } } finally { actions.reloadOrders() + // actions.reloadMangoAccount() setSubmitting(false) } } diff --git a/components/CloseAccountModal.tsx b/components/CloseAccountModal.tsx index 58cfd493..7e6a1abb 100644 --- a/components/CloseAccountModal.tsx +++ b/components/CloseAccountModal.tsx @@ -22,7 +22,6 @@ import { ZERO_BN, ZERO_I80F48, } from '@blockworks-foundation/mango-client' -import usePerpPositions from '../hooks/usePerpPositions' import { formatUsdValue } from '../utils' interface CloseAccountModalProps { @@ -40,7 +39,12 @@ const CloseAccountModal: FunctionComponent = ({ const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current) const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache) - const { openPositions, unsettledPositions } = usePerpPositions() + const openPositions = useMangoStore( + (s) => s.selectedMangoAccount.openPerpPositions + ) + const unsettledPositions = useMangoStore( + (s) => s.selectedMangoAccount.unsettledPerpPositions + ) const [hasBorrows, setHasBorrows] = useState(false) const [hasOpenPositions, setHasOpenPositions] = useState(false) const [totalAccountSOL, setTotalAccountSOL] = useState(0) diff --git a/components/MarketPosition.tsx b/components/MarketPosition.tsx index 23657602..ec4e8e32 100644 --- a/components/MarketPosition.tsx +++ b/components/MarketPosition.tsx @@ -12,14 +12,12 @@ import { 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' @@ -76,9 +74,10 @@ export default function MarketPosition() { const connected = useMangoStore((s) => s.wallet.connected) const setMangoStore = useMangoStore((s) => s.set) const price = useMangoStore((s) => s.tradeForm.price) + const perpAccounts = + useMangoStore.getState().selectedMangoAccount.perpAccounts const baseSymbol = marketConfig.baseSymbol const marketName = marketConfig.name - const tradeHistory = useTradeHistory() const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const [settling, setSettling] = useState(false) @@ -124,19 +123,16 @@ export default function MarketPosition() { return null const { - basePosition, - avgEntryPrice, - breakEvenPrice, - notionalSize, - unsettledPnl, - } = collectPerpPosition( - mangoAccount, - mangoGroup, - mangoCache, - marketConfig, - selectedMarket, - tradeHistory - ) + basePosition = 0, + avgEntryPrice = 0, + breakEvenPrice = 0, + notionalSize = 0, + unsettledPnl = 0, + } = perpAccounts.length + ? perpAccounts.find((pa) => + pa.perpMarket.publicKey.equals(selectedMarket.publicKey) + ) + : {} function SettlePnlTooltip() { return ( diff --git a/components/PerpPositionsTable.tsx b/components/PerpPositionsTable.tsx index 5ec6a8ec..6ed2524a 100644 --- a/components/PerpPositionsTable.tsx +++ b/components/PerpPositionsTable.tsx @@ -1,20 +1,20 @@ import { useCallback, useState } from 'react' import { useRouter } from 'next/router' import Link from 'next/link' -import useMangoStore from '../stores/useMangoStore' +import { useTranslation } from 'next-i18next' import { ExclamationIcon } from '@heroicons/react/outline' + +import useMangoStore from '../stores/useMangoStore' import Button from '../components/Button' import { useViewport } from '../hooks/useViewport' import { breakpoints } from './TradePageGrid' import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements' import { formatUsdValue } from '../utils' import Loading from './Loading' -import usePerpPositions from '../hooks/usePerpPositions' import MarketCloseModal from './MarketCloseModal' import PerpSideBadge from './PerpSideBadge' import PnlText from './PnlText' import { settlePnl } from './MarketPosition' -import { useTranslation } from 'next-i18next' import MobileTableHeader from './mobile/MobileTableHeader' const PositionsTable = () => { @@ -30,7 +30,11 @@ const PositionsTable = () => { const price = useMangoStore((s) => s.tradeForm.price) const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const setMangoStore = useMangoStore((s) => s.set) - const { openPositions, unsettledPositions } = usePerpPositions() + const openPositions = useMangoStore( + (s) => s.selectedMangoAccount.openPerpPositions + ) + const unsettledPositions = + useMangoStore.getState().selectedMangoAccount.unsettledPerpPositions const { width } = useViewport() const isMobile = width ? width < breakpoints.md : false const { asPath } = useRouter() @@ -120,7 +124,6 @@ const PositionsTable = () => { {openPositions.map( ( { - marketIndex, marketConfig, perpMarket, perpAccount, @@ -134,7 +137,10 @@ const PositionsTable = () => { index ) => { return ( - +
{ isOpen={showMarketCloseModal} onClose={handleCloseWarning} market={perpMarket} - marketIndex={marketIndex} + marketIndex={marketConfig.marketIndex} /> ) : null} diff --git a/components/UserInfo.tsx b/components/UserInfo.tsx index 8d6e1b85..0dc0af79 100644 --- a/components/UserInfo.tsx +++ b/components/UserInfo.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react' import useMangoStore from '../stores/useMangoStore' -import usePerpPositions from '../hooks/usePerpPositions' import OpenOrdersTable from './OpenOrdersTable' import BalancesTable from './BalancesTable' import PositionsTable from './PerpPositionsTable' @@ -8,7 +7,6 @@ import TradeHistoryTable from './TradeHistoryTable' import ManualRefresh from './ManualRefresh' import Tabs from './Tabs' import FeeDiscountsTable from './FeeDiscountsTable' -import useMangoAccount from '../hooks/useMangoAccount' import { marketConfigSelector } from '../stores/selectors' const TABS = [ @@ -23,8 +21,10 @@ const UserInfoTabs = ({ activeTab, setActiveTab }) => { const totalOpenOrders = useMangoStore( (s) => s.selectedMangoAccount.totalOpenOrders ) - const { openPositions } = usePerpPositions() - const { mangoAccount } = useMangoAccount() + const totalOpenPerpPositions = useMangoStore( + (s) => s.selectedMangoAccount.totalOpenPerpPositions + ) + const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const handleTabChange = (tabName) => { setActiveTab(tabName) @@ -35,14 +35,10 @@ const UserInfoTabs = ({ activeTab, setActiveTab }) => { 0 && openPositions - ? [ - { tabName: 'Orders', count: totalOpenOrders }, - { tabName: 'Positions', count: openPositions.length }, - ] - : null - } + showCount={[ + { tabName: 'Orders', count: totalOpenOrders }, + { tabName: 'Positions', count: totalOpenPerpPositions }, + ]} tabs={TABS} /> {mangoAccount ? ( diff --git a/hooks/useHydrateStore.tsx b/hooks/useHydrateStore.tsx index 4bd9c2dd..f46bf5ec 100644 --- a/hooks/useHydrateStore.tsx +++ b/hooks/useHydrateStore.tsx @@ -61,7 +61,7 @@ const useHydrateStore = () => { if (mangoAccount) { actions.reloadOrders() } - }, 30 * SECONDS) + }, 20 * SECONDS) useInterval(() => { if (mangoAccount) { diff --git a/hooks/usePerpPositions.tsx b/hooks/usePerpPositions.tsx index 27de8394..5a8b4710 100644 --- a/hooks/usePerpPositions.tsx +++ b/hooks/usePerpPositions.tsx @@ -9,13 +9,14 @@ import { PerpMarketConfig, } from '@blockworks-foundation/mango-client' import useTradeHistory from './useTradeHistory' -import useMangoAccount from './useMangoAccount' import { mangoCacheSelector, mangoGroupConfigSelector, mangoGroupSelector, marketsSelector, } from '../stores/selectors' +import { useEffect } from 'react' +import useMangoAccount from './useMangoAccount' export const collectPerpPosition = ( mangoAccount: MangoAccount, @@ -34,9 +35,8 @@ export const collectPerpPosition = ( ) return {} - const marketIndex = marketConfig.marketIndex - const perpMarketInfo = mangoGroup.perpMarkets[marketIndex] - const perpAccount = mangoAccount.perpAccounts[marketIndex] + const perpMarketInfo = mangoGroup.perpMarkets[marketConfig.marketIndex] + const perpAccount = mangoAccount.perpAccounts[marketConfig.marketIndex] let avgEntryPrice = 0, breakEvenPrice = 0 @@ -52,24 +52,25 @@ export const collectPerpPosition = ( .getBreakEvenPrice(mangoAccount, perpMarket, perpTradeHistory) .toNumber() } catch (e) { - console.error(e) + // console.error(e) } const basePosition = perpMarket?.baseLotsToNumber(perpAccount.basePosition) - const indexPrice = mangoGroup.getPrice(marketIndex, mangoCache).toNumber() + const indexPrice = mangoGroup + .getPrice(marketConfig.marketIndex, mangoCache) + .toNumber() const notionalSize = Math.abs(basePosition * indexPrice) const unrealizedPnl = basePosition * (indexPrice - breakEvenPrice) const unsettledPnl = +nativeI80F48ToUi( perpAccount.getPnl( - mangoGroup.perpMarkets[marketIndex], - mangoCache.perpMarketCache[marketIndex], - mangoCache.priceCache[marketIndex].price + perpMarketInfo, + mangoCache.perpMarketCache[marketConfig.marketIndex], + mangoCache.priceCache[marketConfig.marketIndex].price ), marketConfig.quoteDecimals ).toNumber() return { - marketIndex, perpMarketInfo, marketConfig, perpMarket, @@ -85,6 +86,7 @@ export const collectPerpPosition = ( } const usePerpPositions = () => { + const setMangoStore = useMangoStore((s) => s.set) const { mangoAccount } = useMangoAccount() const groupConfig = useMangoStore(mangoGroupConfigSelector) const mangoGroup = useMangoStore(mangoGroupSelector) @@ -92,29 +94,43 @@ const usePerpPositions = () => { const allMarkets = useMangoStore(marketsSelector) const tradeHistory = useTradeHistory() - const perpAccounts = mangoAccount - ? groupConfig.perpMarkets.map((m) => - collectPerpPosition( - mangoAccount, - mangoGroup, - mangoCache, - m, - allMarkets[m.publicKey.toBase58()] as PerpMarket, - tradeHistory - ) + useEffect(() => { + if (mangoAccount) { + const perpAccounts = mangoAccount + ? groupConfig.perpMarkets.map((m) => + collectPerpPosition( + mangoAccount, + mangoGroup, + mangoCache, + m, + allMarkets[m.publicKey.toBase58()] as PerpMarket, + tradeHistory + ) + ) + : [] + + const openPerpPositions = perpAccounts.filter( + ({ perpAccount }) => + perpAccount?.basePosition && !perpAccount.basePosition.eq(new BN(0)) ) - : [] - const openPositions = perpAccounts.filter( - ({ perpAccount }) => - perpAccount?.basePosition && !perpAccount.basePosition.eq(new BN(0)) - ) - const unsettledPositions = perpAccounts.filter( - ({ perpAccount, unsettledPnl }) => - perpAccount?.basePosition?.eq(new BN(0)) && unsettledPnl != 0 - ) - - return { openPositions, unsettledPositions } + setMangoStore((state) => { + state.selectedMangoAccount.perpAccounts = perpAccounts + state.selectedMangoAccount.openPerpPositions = openPerpPositions + if ( + openPerpPositions.length !== + state.selectedMangoAccount.totalOpenPerpPositions + ) { + state.selectedMangoAccount.totalOpenPerpPositions = + openPerpPositions.length + } + state.selectedMangoAccount.unsettledPerpPositions = perpAccounts.filter( + ({ perpAccount, unsettledPnl }) => + perpAccount?.basePosition?.eq(new BN(0)) && unsettledPnl != 0 + ) + }) + } + }, [mangoAccount, mangoCache]) } export default usePerpPositions diff --git a/pages/_app.tsx b/pages/_app.tsx index 4efdcded..18c57ffc 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -17,12 +17,25 @@ import { appWithTranslation } from 'next-i18next' import ErrorBoundary from '../components/ErrorBoundary' import GlobalNotification from '../components/GlobalNotification' import { useOpenOrders } from '../hooks/useOpenOrders' +import usePerpPositions from '../hooks/usePerpPositions' const MangoStoreUpdater = () => { useHydrateStore() - useWallet() - useOpenOrders() + return null +} +const WalletStoreUpdater = () => { + useWallet() + return null +} + +const OpenOrdersStoreUpdater = () => { + useOpenOrders() + return null +} + +const PerpPositionsStoreUpdater = () => { + usePerpPositions() return null } @@ -93,6 +106,9 @@ function App({ Component, pageProps }) { + + + diff --git a/stores/useMangoStore.tsx b/stores/useMangoStore.tsx index 4ebc0800..90372ac6 100644 --- a/stores/useMangoStore.tsx +++ b/stores/useMangoStore.tsx @@ -167,6 +167,10 @@ interface MangoStore extends State { lastSlot: number openOrders: any[] totalOpenOrders: number + perpAccounts: any[] + openPerpPositions: any[] + totalOpenPerpPositions: number + unsettledPerpPositions: any[] } tradeForm: { side: 'buy' | 'sell' @@ -274,6 +278,10 @@ const useMangoStore = create((set, get) => { lastSlot: 0, openOrders: [], totalOpenOrders: 0, + perpAccounts: [], + openPerpPositions: [], + totalOpenPerpPositions: 0, + unsettledPerpPositions: [], }, tradeForm: { side: 'buy',