utilize zustand for perppositions

This commit is contained in:
Tyler Shipe 2022-01-27 22:57:18 -05:00
parent 8f27393c22
commit a6d432f32d
9 changed files with 114 additions and 71 deletions

View File

@ -132,6 +132,7 @@ const BalancesTable = ({
} }
} finally { } finally {
actions.reloadOrders() actions.reloadOrders()
// actions.reloadMangoAccount()
setSubmitting(false) setSubmitting(false)
} }
} }

View File

@ -22,7 +22,6 @@ import {
ZERO_BN, ZERO_BN,
ZERO_I80F48, ZERO_I80F48,
} from '@blockworks-foundation/mango-client' } from '@blockworks-foundation/mango-client'
import usePerpPositions from '../hooks/usePerpPositions'
import { formatUsdValue } from '../utils' import { formatUsdValue } from '../utils'
interface CloseAccountModalProps { interface CloseAccountModalProps {
@ -40,7 +39,12 @@ const CloseAccountModal: FunctionComponent<CloseAccountModalProps> = ({
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current) const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache) 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 [hasBorrows, setHasBorrows] = useState(false)
const [hasOpenPositions, setHasOpenPositions] = useState(false) const [hasOpenPositions, setHasOpenPositions] = useState(false)
const [totalAccountSOL, setTotalAccountSOL] = useState(0) const [totalAccountSOL, setTotalAccountSOL] = useState(0)

View File

@ -12,14 +12,12 @@ import {
PerpMarket, PerpMarket,
QUOTE_INDEX, QUOTE_INDEX,
} from '@blockworks-foundation/mango-client' } from '@blockworks-foundation/mango-client'
import useTradeHistory from '../hooks/useTradeHistory'
import { notify } from '../utils/notifications' import { notify } from '../utils/notifications'
import MarketCloseModal from './MarketCloseModal' import MarketCloseModal from './MarketCloseModal'
import PnlText from './PnlText' import PnlText from './PnlText'
import Loading from './Loading' import Loading from './Loading'
import { useViewport } from '../hooks/useViewport' import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid' import { breakpoints } from './TradePageGrid'
import { collectPerpPosition } from '../hooks/usePerpPositions'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
import useMangoAccount from '../hooks/useMangoAccount' import useMangoAccount from '../hooks/useMangoAccount'
@ -76,9 +74,10 @@ export default function MarketPosition() {
const connected = useMangoStore((s) => s.wallet.connected) const connected = useMangoStore((s) => s.wallet.connected)
const setMangoStore = useMangoStore((s) => s.set) const setMangoStore = useMangoStore((s) => s.set)
const price = useMangoStore((s) => s.tradeForm.price) const price = useMangoStore((s) => s.tradeForm.price)
const perpAccounts =
useMangoStore.getState().selectedMangoAccount.perpAccounts
const baseSymbol = marketConfig.baseSymbol const baseSymbol = marketConfig.baseSymbol
const marketName = marketConfig.name const marketName = marketConfig.name
const tradeHistory = useTradeHistory()
const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const [showMarketCloseModal, setShowMarketCloseModal] = useState(false)
const [settling, setSettling] = useState(false) const [settling, setSettling] = useState(false)
@ -124,19 +123,16 @@ export default function MarketPosition() {
return null return null
const { const {
basePosition, basePosition = 0,
avgEntryPrice, avgEntryPrice = 0,
breakEvenPrice, breakEvenPrice = 0,
notionalSize, notionalSize = 0,
unsettledPnl, unsettledPnl = 0,
} = collectPerpPosition( } = perpAccounts.length
mangoAccount, ? perpAccounts.find((pa) =>
mangoGroup, pa.perpMarket.publicKey.equals(selectedMarket.publicKey)
mangoCache, )
marketConfig, : {}
selectedMarket,
tradeHistory
)
function SettlePnlTooltip() { function SettlePnlTooltip() {
return ( return (

View File

@ -1,20 +1,20 @@
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import Link from 'next/link' import Link from 'next/link'
import useMangoStore from '../stores/useMangoStore' import { useTranslation } from 'next-i18next'
import { ExclamationIcon } from '@heroicons/react/outline' import { ExclamationIcon } from '@heroicons/react/outline'
import useMangoStore from '../stores/useMangoStore'
import Button from '../components/Button' import Button from '../components/Button'
import { useViewport } from '../hooks/useViewport' import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid' import { breakpoints } from './TradePageGrid'
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements' import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
import { formatUsdValue } from '../utils' import { formatUsdValue } from '../utils'
import Loading from './Loading' import Loading from './Loading'
import usePerpPositions from '../hooks/usePerpPositions'
import MarketCloseModal from './MarketCloseModal' import MarketCloseModal from './MarketCloseModal'
import PerpSideBadge from './PerpSideBadge' import PerpSideBadge from './PerpSideBadge'
import PnlText from './PnlText' import PnlText from './PnlText'
import { settlePnl } from './MarketPosition' import { settlePnl } from './MarketPosition'
import { useTranslation } from 'next-i18next'
import MobileTableHeader from './mobile/MobileTableHeader' import MobileTableHeader from './mobile/MobileTableHeader'
const PositionsTable = () => { const PositionsTable = () => {
@ -30,7 +30,11 @@ const PositionsTable = () => {
const price = useMangoStore((s) => s.tradeForm.price) const price = useMangoStore((s) => s.tradeForm.price)
const [showMarketCloseModal, setShowMarketCloseModal] = useState(false) const [showMarketCloseModal, setShowMarketCloseModal] = useState(false)
const setMangoStore = useMangoStore((s) => s.set) 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 { width } = useViewport()
const isMobile = width ? width < breakpoints.md : false const isMobile = width ? width < breakpoints.md : false
const { asPath } = useRouter() const { asPath } = useRouter()
@ -120,7 +124,6 @@ const PositionsTable = () => {
{openPositions.map( {openPositions.map(
( (
{ {
marketIndex,
marketConfig, marketConfig,
perpMarket, perpMarket,
perpAccount, perpAccount,
@ -134,7 +137,10 @@ const PositionsTable = () => {
index index
) => { ) => {
return ( return (
<TrBody index={index} key={`${marketIndex}`}> <TrBody
index={index}
key={`${marketConfig.marketIndex}`}
>
<Td> <Td>
<div className="flex items-center"> <div className="flex items-center">
<img <img
@ -215,7 +221,7 @@ const PositionsTable = () => {
isOpen={showMarketCloseModal} isOpen={showMarketCloseModal}
onClose={handleCloseWarning} onClose={handleCloseWarning}
market={perpMarket} market={perpMarket}
marketIndex={marketIndex} marketIndex={marketConfig.marketIndex}
/> />
) : null} ) : null}
</TrBody> </TrBody>

View File

@ -1,6 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import useMangoStore from '../stores/useMangoStore' import useMangoStore from '../stores/useMangoStore'
import usePerpPositions from '../hooks/usePerpPositions'
import OpenOrdersTable from './OpenOrdersTable' import OpenOrdersTable from './OpenOrdersTable'
import BalancesTable from './BalancesTable' import BalancesTable from './BalancesTable'
import PositionsTable from './PerpPositionsTable' import PositionsTable from './PerpPositionsTable'
@ -8,7 +7,6 @@ import TradeHistoryTable from './TradeHistoryTable'
import ManualRefresh from './ManualRefresh' import ManualRefresh from './ManualRefresh'
import Tabs from './Tabs' import Tabs from './Tabs'
import FeeDiscountsTable from './FeeDiscountsTable' import FeeDiscountsTable from './FeeDiscountsTable'
import useMangoAccount from '../hooks/useMangoAccount'
import { marketConfigSelector } from '../stores/selectors' import { marketConfigSelector } from '../stores/selectors'
const TABS = [ const TABS = [
@ -23,8 +21,10 @@ const UserInfoTabs = ({ activeTab, setActiveTab }) => {
const totalOpenOrders = useMangoStore( const totalOpenOrders = useMangoStore(
(s) => s.selectedMangoAccount.totalOpenOrders (s) => s.selectedMangoAccount.totalOpenOrders
) )
const { openPositions } = usePerpPositions() const totalOpenPerpPositions = useMangoStore(
const { mangoAccount } = useMangoAccount() (s) => s.selectedMangoAccount.totalOpenPerpPositions
)
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const handleTabChange = (tabName) => { const handleTabChange = (tabName) => {
setActiveTab(tabName) setActiveTab(tabName)
@ -35,14 +35,10 @@ const UserInfoTabs = ({ activeTab, setActiveTab }) => {
<Tabs <Tabs
activeTab={activeTab} activeTab={activeTab}
onChange={handleTabChange} onChange={handleTabChange}
showCount={ showCount={[
totalOpenOrders > 0 && openPositions { tabName: 'Orders', count: totalOpenOrders },
? [ { tabName: 'Positions', count: totalOpenPerpPositions },
{ tabName: 'Orders', count: totalOpenOrders }, ]}
{ tabName: 'Positions', count: openPositions.length },
]
: null
}
tabs={TABS} tabs={TABS}
/> />
{mangoAccount ? ( {mangoAccount ? (

View File

@ -61,7 +61,7 @@ const useHydrateStore = () => {
if (mangoAccount) { if (mangoAccount) {
actions.reloadOrders() actions.reloadOrders()
} }
}, 30 * SECONDS) }, 20 * SECONDS)
useInterval(() => { useInterval(() => {
if (mangoAccount) { if (mangoAccount) {

View File

@ -9,13 +9,14 @@ import {
PerpMarketConfig, PerpMarketConfig,
} from '@blockworks-foundation/mango-client' } from '@blockworks-foundation/mango-client'
import useTradeHistory from './useTradeHistory' import useTradeHistory from './useTradeHistory'
import useMangoAccount from './useMangoAccount'
import { import {
mangoCacheSelector, mangoCacheSelector,
mangoGroupConfigSelector, mangoGroupConfigSelector,
mangoGroupSelector, mangoGroupSelector,
marketsSelector, marketsSelector,
} from '../stores/selectors' } from '../stores/selectors'
import { useEffect } from 'react'
import useMangoAccount from './useMangoAccount'
export const collectPerpPosition = ( export const collectPerpPosition = (
mangoAccount: MangoAccount, mangoAccount: MangoAccount,
@ -34,9 +35,8 @@ export const collectPerpPosition = (
) )
return {} return {}
const marketIndex = marketConfig.marketIndex const perpMarketInfo = mangoGroup.perpMarkets[marketConfig.marketIndex]
const perpMarketInfo = mangoGroup.perpMarkets[marketIndex] const perpAccount = mangoAccount.perpAccounts[marketConfig.marketIndex]
const perpAccount = mangoAccount.perpAccounts[marketIndex]
let avgEntryPrice = 0, let avgEntryPrice = 0,
breakEvenPrice = 0 breakEvenPrice = 0
@ -52,24 +52,25 @@ export const collectPerpPosition = (
.getBreakEvenPrice(mangoAccount, perpMarket, perpTradeHistory) .getBreakEvenPrice(mangoAccount, perpMarket, perpTradeHistory)
.toNumber() .toNumber()
} catch (e) { } catch (e) {
console.error(e) // console.error(e)
} }
const basePosition = perpMarket?.baseLotsToNumber(perpAccount.basePosition) 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 notionalSize = Math.abs(basePosition * indexPrice)
const unrealizedPnl = basePosition * (indexPrice - breakEvenPrice) const unrealizedPnl = basePosition * (indexPrice - breakEvenPrice)
const unsettledPnl = +nativeI80F48ToUi( const unsettledPnl = +nativeI80F48ToUi(
perpAccount.getPnl( perpAccount.getPnl(
mangoGroup.perpMarkets[marketIndex], perpMarketInfo,
mangoCache.perpMarketCache[marketIndex], mangoCache.perpMarketCache[marketConfig.marketIndex],
mangoCache.priceCache[marketIndex].price mangoCache.priceCache[marketConfig.marketIndex].price
), ),
marketConfig.quoteDecimals marketConfig.quoteDecimals
).toNumber() ).toNumber()
return { return {
marketIndex,
perpMarketInfo, perpMarketInfo,
marketConfig, marketConfig,
perpMarket, perpMarket,
@ -85,6 +86,7 @@ export const collectPerpPosition = (
} }
const usePerpPositions = () => { const usePerpPositions = () => {
const setMangoStore = useMangoStore((s) => s.set)
const { mangoAccount } = useMangoAccount() const { mangoAccount } = useMangoAccount()
const groupConfig = useMangoStore(mangoGroupConfigSelector) const groupConfig = useMangoStore(mangoGroupConfigSelector)
const mangoGroup = useMangoStore(mangoGroupSelector) const mangoGroup = useMangoStore(mangoGroupSelector)
@ -92,29 +94,43 @@ const usePerpPositions = () => {
const allMarkets = useMangoStore(marketsSelector) const allMarkets = useMangoStore(marketsSelector)
const tradeHistory = useTradeHistory() const tradeHistory = useTradeHistory()
const perpAccounts = mangoAccount useEffect(() => {
? groupConfig.perpMarkets.map((m) => if (mangoAccount) {
collectPerpPosition( const perpAccounts = mangoAccount
mangoAccount, ? groupConfig.perpMarkets.map((m) =>
mangoGroup, collectPerpPosition(
mangoCache, mangoAccount,
m, mangoGroup,
allMarkets[m.publicKey.toBase58()] as PerpMarket, mangoCache,
tradeHistory 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( setMangoStore((state) => {
({ perpAccount }) => state.selectedMangoAccount.perpAccounts = perpAccounts
perpAccount?.basePosition && !perpAccount.basePosition.eq(new BN(0)) state.selectedMangoAccount.openPerpPositions = openPerpPositions
) if (
const unsettledPositions = perpAccounts.filter( openPerpPositions.length !==
({ perpAccount, unsettledPnl }) => state.selectedMangoAccount.totalOpenPerpPositions
perpAccount?.basePosition?.eq(new BN(0)) && unsettledPnl != 0 ) {
) state.selectedMangoAccount.totalOpenPerpPositions =
openPerpPositions.length
return { openPositions, unsettledPositions } }
state.selectedMangoAccount.unsettledPerpPositions = perpAccounts.filter(
({ perpAccount, unsettledPnl }) =>
perpAccount?.basePosition?.eq(new BN(0)) && unsettledPnl != 0
)
})
}
}, [mangoAccount, mangoCache])
} }
export default usePerpPositions export default usePerpPositions

View File

@ -17,12 +17,25 @@ import { appWithTranslation } from 'next-i18next'
import ErrorBoundary from '../components/ErrorBoundary' import ErrorBoundary from '../components/ErrorBoundary'
import GlobalNotification from '../components/GlobalNotification' import GlobalNotification from '../components/GlobalNotification'
import { useOpenOrders } from '../hooks/useOpenOrders' import { useOpenOrders } from '../hooks/useOpenOrders'
import usePerpPositions from '../hooks/usePerpPositions'
const MangoStoreUpdater = () => { const MangoStoreUpdater = () => {
useHydrateStore() useHydrateStore()
useWallet() return null
useOpenOrders() }
const WalletStoreUpdater = () => {
useWallet()
return null
}
const OpenOrdersStoreUpdater = () => {
useOpenOrders()
return null
}
const PerpPositionsStoreUpdater = () => {
usePerpPositions()
return null return null
} }
@ -93,6 +106,9 @@ function App({ Component, pageProps }) {
<ErrorBoundary> <ErrorBoundary>
<PageTitle /> <PageTitle />
<MangoStoreUpdater /> <MangoStoreUpdater />
<WalletStoreUpdater />
<OpenOrdersStoreUpdater />
<PerpPositionsStoreUpdater />
</ErrorBoundary> </ErrorBoundary>
<ThemeProvider defaultTheme="Mango"> <ThemeProvider defaultTheme="Mango">

View File

@ -167,6 +167,10 @@ interface MangoStore extends State {
lastSlot: number lastSlot: number
openOrders: any[] openOrders: any[]
totalOpenOrders: number totalOpenOrders: number
perpAccounts: any[]
openPerpPositions: any[]
totalOpenPerpPositions: number
unsettledPerpPositions: any[]
} }
tradeForm: { tradeForm: {
side: 'buy' | 'sell' side: 'buy' | 'sell'
@ -274,6 +278,10 @@ const useMangoStore = create<MangoStore>((set, get) => {
lastSlot: 0, lastSlot: 0,
openOrders: [], openOrders: [],
totalOpenOrders: 0, totalOpenOrders: 0,
perpAccounts: [],
openPerpPositions: [],
totalOpenPerpPositions: 0,
unsettledPerpPositions: [],
}, },
tradeForm: { tradeForm: {
side: 'buy', side: 'buy',