add ws watching for mangoAccount
This commit is contained in:
parent
78a45ebe96
commit
855a6e6d58
|
@ -27,6 +27,13 @@ import { useTranslation } from 'next-i18next'
|
|||
import FloatingElement from './FloatingElement'
|
||||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
import { ORDERBOOK_FLASH_KEY } from './SettingsModal'
|
||||
import {
|
||||
mangoGroupConfigSelector,
|
||||
marketConfigSelector,
|
||||
marketSelector,
|
||||
orderbookSelector,
|
||||
setStoreSelector,
|
||||
} from '../stores/selectors'
|
||||
|
||||
const Line = (props) => {
|
||||
return (
|
||||
|
@ -112,10 +119,10 @@ const hasOpenOrderForPriceGroup = (openOrderPrices, price, grouping) => {
|
|||
|
||||
export default function Orderbook({ depth = 8 }) {
|
||||
const { t } = useTranslation('common')
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const orderbook = useMangoStore((s) => s.selectedMarket.orderBook)
|
||||
const market = useMangoStore((s) => s.selectedMarket.current)
|
||||
const groupConfig = useMangoStore(mangoGroupConfigSelector)
|
||||
const marketConfig = useMangoStore(marketConfigSelector)
|
||||
const orderbook = useMangoStore(orderbookSelector)
|
||||
const market = useMangoStore(marketSelector)
|
||||
const markPrice = useMarkPrice()
|
||||
const openOrders = useOpenOrders()
|
||||
const openOrderPrices = openOrders?.length
|
||||
|
@ -593,7 +600,7 @@ const OrderbookRow = React.memo<any>(
|
|||
grouping,
|
||||
}) => {
|
||||
const element = useRef(null)
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const setMangoStore = useMangoStore(setStoreSelector)
|
||||
const [showOrderbookFlash] = useLocalStorageState(ORDERBOOK_FLASH_KEY, true)
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -2,33 +2,34 @@ import { useCallback, useState } from 'react'
|
|||
import { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { ExclamationIcon } from '@heroicons/react/outline'
|
||||
import Button from '../components/Button'
|
||||
// import { ExclamationIcon } from '@heroicons/react/outline'
|
||||
// import Button from '../components/Button'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
import { breakpoints } from './TradePageGrid'
|
||||
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
|
||||
import { formatUsdValue } from '../utils'
|
||||
import Loading from './Loading'
|
||||
// import Loading from './Loading'
|
||||
import usePerpPositions from '../hooks/usePerpPositions'
|
||||
import MarketCloseModal from './MarketCloseModal'
|
||||
import { ExpandableRow } from './TableElements'
|
||||
import PerpSideBadge from './PerpSideBadge'
|
||||
import PnlText from './PnlText'
|
||||
import { settlePnl } from './MarketPosition'
|
||||
// import { settlePnl } from './MarketPosition'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import MobileTableHeader from './mobile/MobileTableHeader'
|
||||
|
||||
const PositionsTable = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const { reloadMangoAccount } = useMangoStore((s) => s.actions)
|
||||
const [settling, setSettling] = useState(false)
|
||||
// const { reloadMangoAccount } = useMangoStore((s) => s.actions)
|
||||
// const [settling, setSettling] = useState(false)
|
||||
|
||||
const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
|
||||
const selectedMarketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const price = useMangoStore((s) => s.tradeForm.price)
|
||||
const [showMarketCloseModal, setShowMarketCloseModal] = useState(false)
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const { openPositions, unsettledPositions } = usePerpPositions()
|
||||
// const { openPositions, unsettledPositions } = usePerpPositions()
|
||||
const { openPositions } = usePerpPositions()
|
||||
const { width } = useViewport()
|
||||
const isMobile = width ? width < breakpoints.md : false
|
||||
const { asPath } = useRouter()
|
||||
|
@ -49,18 +50,18 @@ const PositionsTable = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const handleSettleAll = async () => {
|
||||
setSettling(true)
|
||||
await Promise.all(
|
||||
unsettledPositions.map((p) => settlePnl(p.perpMarket, p.perpAccount, t))
|
||||
)
|
||||
await reloadMangoAccount()
|
||||
setSettling(false)
|
||||
}
|
||||
// const handleSettleAll = async () => {
|
||||
// setSettling(true)
|
||||
// await Promise.all(
|
||||
// unsettledPositions.map((p) => settlePnl(p.perpMarket, p.perpAccount, t))
|
||||
// )
|
||||
// await reloadMangoAccount()
|
||||
// setSettling(false)
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="flex flex-col pb-2 pt-4">
|
||||
{unsettledPositions.length > 0 ? (
|
||||
{/* {unsettledPositions.length > 0 ? (
|
||||
<div className="border border-th-bkg-4 rounded-lg mb-6 p-4 sm:p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center sm:text-lg">
|
||||
|
@ -95,7 +96,7 @@ const PositionsTable = () => {
|
|||
)
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
) : null} */}
|
||||
<div className={`md:-my-2 md:overflow-x-auto`}>
|
||||
<div className={`align-middle inline-block min-w-full`}>
|
||||
{openPositions.length ? (
|
||||
|
|
|
@ -11,6 +11,7 @@ import ManualRefresh from './ManualRefresh'
|
|||
import Tabs from './Tabs'
|
||||
import FeeDiscountsTable from './FeeDiscountsTable'
|
||||
import useMangoAccount from '../hooks/useMangoAccount'
|
||||
import { connectionSelector, marketConfigSelector } from '../stores/selectors'
|
||||
|
||||
const TABS = [
|
||||
'Balances',
|
||||
|
@ -24,7 +25,7 @@ const UserInfoTabs = ({ activeTab, setActiveTab }) => {
|
|||
const openOrders = useOpenOrders()
|
||||
const { openPositions } = usePerpPositions()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const connected = useMangoStore((s) => s.connection.current)
|
||||
const connected = useMangoStore(connectionSelector)
|
||||
|
||||
const handleTabChange = (tabName) => {
|
||||
setActiveTab(tabName)
|
||||
|
@ -72,7 +73,7 @@ const TabContent = ({ activeTab }) => {
|
|||
}
|
||||
|
||||
const UserInfo = () => {
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const marketConfig = useMangoStore(marketConfigSelector)
|
||||
const isPerpMarket = marketConfig.kind === 'perp'
|
||||
const [activeTab, setActiveTab] = useState('')
|
||||
|
||||
|
|
|
@ -6,8 +6,16 @@ import { Orderbook as SpotOrderBook, Market } from '@project-serum/serum'
|
|||
import {
|
||||
BookSide,
|
||||
BookSideLayout,
|
||||
MangoAccountLayout,
|
||||
PerpMarket,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
import {
|
||||
actionsSelector,
|
||||
connectionSelector,
|
||||
marketConfigSelector,
|
||||
marketSelector,
|
||||
marketsSelector,
|
||||
} from '../stores/selectors'
|
||||
|
||||
const SECONDS = 1000
|
||||
const _SLOW_REFRESH_INTERVAL = 20 * SECONDS
|
||||
|
@ -33,12 +41,12 @@ function decodeBook(market, accInfo: AccountInfo<Buffer>): number[][] {
|
|||
|
||||
const useHydrateStore = () => {
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
const markets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const market = useMangoStore((state) => state.selectedMarket.current)
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
|
||||
const connection = useMangoStore((s) => s.connection.current)
|
||||
const actions = useMangoStore(actionsSelector)
|
||||
const markets = useMangoStore(marketsSelector)
|
||||
const marketConfig = useMangoStore(marketConfigSelector)
|
||||
const selectedMarket = useMangoStore(marketSelector)
|
||||
const connection = useMangoStore(connectionSelector)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
|
||||
useEffect(() => {
|
||||
actions.fetchMangoGroup()
|
||||
|
@ -67,11 +75,37 @@ const useHydrateStore = () => {
|
|||
})
|
||||
}, [marketConfig, markets, setMangoStore])
|
||||
|
||||
useEffect(() => {
|
||||
if (!mangoAccount) return
|
||||
console.log('in mango account WS useEffect')
|
||||
const subscriptionId = connection.onAccountChange(
|
||||
mangoAccount.publicKey,
|
||||
(info) => {
|
||||
console.log('mango account WS update: ', info)
|
||||
|
||||
const decodedMangoAccount = MangoAccountLayout.decode(info?.data)
|
||||
const newMangoAccount = Object.assign(mangoAccount, decodedMangoAccount)
|
||||
|
||||
// const lastSlot = useMangoStore.getState().connection.slot
|
||||
|
||||
setMangoStore((state) => {
|
||||
state.selectedMangoAccount.current = newMangoAccount
|
||||
state.selectedMangoAccount.lastUpdatedAt = new Date().toISOString()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return () => {
|
||||
connection.removeAccountChangeListener(subscriptionId)
|
||||
}
|
||||
}, [mangoAccount])
|
||||
|
||||
// hydrate orderbook with all markets in mango group
|
||||
useEffect(() => {
|
||||
let previousBidInfo: AccountInfo<Buffer> | null = null
|
||||
let previousAskInfo: AccountInfo<Buffer> | null = null
|
||||
if (!marketConfig || !market) return
|
||||
if (!marketConfig || !selectedMarket) return
|
||||
console.log('in orderbook WS useEffect')
|
||||
|
||||
const bidSubscriptionId = connection.onAccountChange(
|
||||
marketConfig.bidsKey,
|
||||
|
@ -86,7 +120,10 @@ const useHydrateStore = () => {
|
|||
previousBidInfo = info
|
||||
setMangoStore((state) => {
|
||||
state.accountInfos[marketConfig.bidsKey.toString()] = info
|
||||
state.selectedMarket.orderBook.bids = decodeBook(market, info)
|
||||
state.selectedMarket.orderBook.bids = decodeBook(
|
||||
selectedMarket,
|
||||
info
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +141,10 @@ const useHydrateStore = () => {
|
|||
previousAskInfo = info
|
||||
setMangoStore((state) => {
|
||||
state.accountInfos[marketConfig.asksKey.toString()] = info
|
||||
state.selectedMarket.orderBook.asks = decodeBook(market, info)
|
||||
state.selectedMarket.orderBook.asks = decodeBook(
|
||||
selectedMarket,
|
||||
info
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +154,7 @@ const useHydrateStore = () => {
|
|||
connection.removeAccountChangeListener(bidSubscriptionId)
|
||||
connection.removeAccountChangeListener(askSubscriptionId)
|
||||
}
|
||||
}, [marketConfig, market, connection, setMangoStore])
|
||||
}, [marketConfig, selectedMarket, connection, setMangoStore])
|
||||
|
||||
// fetch filled trades for selected market
|
||||
useInterval(() => {
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import { useEffect } from 'react'
|
||||
import {
|
||||
fillsSelector,
|
||||
marketSelector,
|
||||
markPriceSelector,
|
||||
orderbookSelector,
|
||||
setStoreSelector,
|
||||
} from '../stores/selectors'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { getDecimalCount } from '../utils'
|
||||
|
||||
export default function useMarkPrice() {
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const markPrice = useMangoStore((s) => s.selectedMarket.markPrice)
|
||||
const orderbook = useMangoStore((s) => s.selectedMarket.orderBook)
|
||||
const fills = useMangoStore((state) => state.selectedMarket.fills)
|
||||
const market = useMangoStore((s) => s.selectedMarket.current)
|
||||
const setMangoStore = useMangoStore(setStoreSelector)
|
||||
const markPrice = useMangoStore(markPriceSelector)
|
||||
const orderbook = useMangoStore(orderbookSelector)
|
||||
const fills = useMangoStore(fillsSelector)
|
||||
const market = useMangoStore(marketSelector)
|
||||
|
||||
const trades = fills
|
||||
.filter((trade) => trade?.eventFlags?.maker || trade?.maker)
|
||||
|
|
|
@ -11,6 +11,12 @@ import {
|
|||
import { Market, Orderbook } from '@project-serum/serum'
|
||||
import { Order } from '@project-serum/serum/lib/market'
|
||||
import { PerpTriggerOrder } from '../@types/types'
|
||||
import {
|
||||
accountInfosSelector,
|
||||
mangoGroupConfigSelector,
|
||||
mangoGroupSelector,
|
||||
marketsSelector,
|
||||
} from '../stores/selectors'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import useMangoAccount from './useMangoAccount'
|
||||
|
||||
|
@ -102,11 +108,11 @@ function parsePerpOpenOrders(
|
|||
}
|
||||
|
||||
export function useOpenOrders() {
|
||||
const markets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const markets = useMangoStore(marketsSelector)
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const accountInfos = useMangoStore((s) => s.accountInfos)
|
||||
const mangoGroup = useMangoStore(mangoGroupSelector)
|
||||
const groupConfig = useMangoStore(mangoGroupConfigSelector)
|
||||
const accountInfos = useMangoStore(accountInfosSelector)
|
||||
|
||||
if (!mangoGroup || !mangoAccount || !accountInfos) return null
|
||||
|
||||
|
|
|
@ -10,6 +10,12 @@ import {
|
|||
} from '@blockworks-foundation/mango-client'
|
||||
import useTradeHistory from './useTradeHistory'
|
||||
import useMangoAccount from './useMangoAccount'
|
||||
import {
|
||||
mangoCacheSelector,
|
||||
mangoGroupConfigSelector,
|
||||
mangoGroupSelector,
|
||||
marketsSelector,
|
||||
} from '../stores/selectors'
|
||||
|
||||
export const collectPerpPosition = (
|
||||
mangoAccount: MangoAccount,
|
||||
|
@ -80,10 +86,10 @@ export const collectPerpPosition = (
|
|||
|
||||
const usePerpPositions = () => {
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
|
||||
const allMarkets = useMangoStore((s) => s.selectedMangoGroup.markets)
|
||||
const groupConfig = useMangoStore(mangoGroupConfigSelector)
|
||||
const mangoGroup = useMangoStore(mangoGroupSelector)
|
||||
const mangoCache = useMangoStore(mangoCacheSelector)
|
||||
const allMarkets = useMangoStore(marketsSelector)
|
||||
const tradeHistory = useTradeHistory()
|
||||
|
||||
const perpAccounts = mangoAccount
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import { getMarketByPublicKey } from '@blockworks-foundation/mango-client'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import {
|
||||
fillsSelector,
|
||||
mangoAccountSelector,
|
||||
mangoGroupSelector,
|
||||
marketConfigSelector,
|
||||
tradeHistorySelector,
|
||||
} from '../stores/selectors'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
|
||||
const byTimestamp = (a, b) => {
|
||||
|
@ -77,11 +84,11 @@ const formatTradeHistory = (mangoAccountPk: PublicKey, newTradeHistory) => {
|
|||
export const useTradeHistory = (
|
||||
opts: { excludePerpLiquidations?: boolean } = {}
|
||||
) => {
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const fills = useMangoStore((s) => s.selectedMarket.fills)
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
let tradeHistory = useMangoStore((s) => s.tradeHistory)
|
||||
const marketConfig = useMangoStore(marketConfigSelector)
|
||||
const fills = useMangoStore(fillsSelector)
|
||||
const mangoAccount = useMangoStore(mangoAccountSelector)
|
||||
const selectedMangoGroup = useMangoStore(mangoGroupSelector)
|
||||
let tradeHistory = useMangoStore(tradeHistorySelector)
|
||||
|
||||
if (!mangoAccount || !selectedMangoGroup) return null
|
||||
const openOrdersAccount =
|
||||
|
|
|
@ -159,7 +159,7 @@ export default function useWallet() {
|
|||
if (connected && mangoAccount) {
|
||||
actions.reloadMangoAccount()
|
||||
}
|
||||
}, 20 * SECONDS)
|
||||
}, 90 * SECONDS)
|
||||
|
||||
return { connected, wallet }
|
||||
}
|
||||
|
|
|
@ -15,9 +15,14 @@ import { ViewportProvider } from '../hooks/useViewport'
|
|||
import BottomBar from '../components/mobile/BottomBar'
|
||||
import { appWithTranslation } from 'next-i18next'
|
||||
|
||||
function App({ Component, pageProps }) {
|
||||
const MangoStoreUpdater = () => {
|
||||
useHydrateStore()
|
||||
useWallet()
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function App({ Component, pageProps }) {
|
||||
const marketConfig = useMangoStore((s) => s.selectedMarket.config)
|
||||
const market = useMangoStore((s) => s.selectedMarket.current)
|
||||
const oraclePrice = useOraclePrice()
|
||||
|
@ -72,6 +77,7 @@ function App({ Component, pageProps }) {
|
|||
|
||||
<link rel="manifest" href="/manifest.json"></link>
|
||||
</Head>
|
||||
<MangoStoreUpdater />
|
||||
<ThemeProvider defaultTheme="Mango">
|
||||
<ViewportProvider>
|
||||
<div className="bg-th-bkg-1">
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// It is generally recommended to define selectors outside the render function.
|
||||
// This will prevent unnecessary computations each render.
|
||||
// It also allows React to optimize performance in concurrent mode.
|
||||
|
||||
export const mangoAccountSelector = (state) =>
|
||||
state.selectedMangoAccount.current
|
||||
|
||||
export const mangoGroupSelector = (state) => state.selectedMangoGroup.current
|
||||
|
||||
export const mangoGroupConfigSelector = (state) =>
|
||||
state.selectedMangoGroup.config
|
||||
|
||||
export const mangoCacheSelector = (state) => state.selectedMangoGroup.cache
|
||||
|
||||
export const actionsSelector = (state) => state.actions
|
||||
|
||||
export const marketsSelector = (state) => state.selectedMangoGroup.markets
|
||||
|
||||
export const marketSelector = (state) => state.selectedMarket.current
|
||||
|
||||
export const marketConfigSelector = (state) => state.selectedMarket.config
|
||||
|
||||
export const connectionSelector = (state) => state.connection.current
|
||||
|
||||
export const orderbookSelector = (state) => state.selectedMarket.orderBook
|
||||
|
||||
export const markPriceSelector = (state) => state.selectedMarket.markPrice
|
||||
|
||||
export const fillsSelector = (state) => state.selectedMarket.fills
|
||||
|
||||
export const setStoreSelector = (state) => state.set
|
||||
|
||||
export const accountInfosSelector = (state) => state.accountInfos
|
||||
|
||||
export const tradeHistorySelector = (state) => state.tradeHistory
|
|
@ -470,12 +470,12 @@ const useMangoStore = create<MangoStore>((set, get) => {
|
|||
connection,
|
||||
mangoClient.lastSlot
|
||||
)
|
||||
console.log('reloading mango account')
|
||||
|
||||
set((state) => {
|
||||
state.selectedMangoAccount.current = reloadedMangoAccount
|
||||
state.selectedMangoAccount.lastUpdatedAt = new Date().toISOString()
|
||||
})
|
||||
console.log('reloaded mango account', reloadedMangoAccount)
|
||||
},
|
||||
async reloadOrders() {
|
||||
const mangoAccount = get().selectedMangoAccount.current
|
||||
|
|
Loading…
Reference in New Issue