2021-04-06 15:11:42 -07:00
|
|
|
import { useEffect } from 'react'
|
|
|
|
import { Market } from '@project-serum/serum'
|
2021-04-29 08:08:36 -07:00
|
|
|
import { AccountInfo } from '@solana/web3.js'
|
2021-04-06 15:11:42 -07:00
|
|
|
import useConnection from './useConnection'
|
|
|
|
import useMangoStore from '../stores/useMangoStore'
|
2021-04-12 21:40:26 -07:00
|
|
|
import useSerumStore from '../stores/useSerumStore'
|
2021-04-07 08:44:22 -07:00
|
|
|
import useMarketList from './useMarketList'
|
2021-04-12 21:40:26 -07:00
|
|
|
import useInterval from './useInterval'
|
|
|
|
|
2021-04-26 12:17:57 -07:00
|
|
|
const SECONDS = 1000
|
2021-04-29 08:08:36 -07:00
|
|
|
const _SLOW_REFRESH_INTERVAL = 60 * SECONDS
|
2021-04-07 08:44:22 -07:00
|
|
|
|
|
|
|
const mangoGroupMarketsSelector = (s) => s.selectedMangoGroup.markets
|
2021-04-20 14:00:45 -07:00
|
|
|
const websocketConnectionSelector = (s) => s.connection.websocket
|
2021-04-06 15:11:42 -07:00
|
|
|
|
|
|
|
const useHydrateStore = () => {
|
|
|
|
const setMangoStore = useMangoStore((s) => s.set)
|
2021-04-12 21:40:26 -07:00
|
|
|
const setSerumStore = useSerumStore((s) => s.set)
|
2021-04-07 08:44:22 -07:00
|
|
|
const marketsForSelectedMangoGroup = useMangoStore(mangoGroupMarketsSelector)
|
2021-04-20 14:00:45 -07:00
|
|
|
const websocketConnection = useMangoStore(websocketConnectionSelector)
|
2021-04-14 23:16:36 -07:00
|
|
|
const actions = useMangoStore((s) => s.actions)
|
2021-04-29 08:08:36 -07:00
|
|
|
const { connection } = useConnection()
|
2021-04-07 08:44:22 -07:00
|
|
|
const { marketList } = useMarketList()
|
2021-04-06 15:11:42 -07:00
|
|
|
|
2021-04-14 23:16:36 -07:00
|
|
|
useEffect(() => {
|
2021-04-24 19:10:28 -07:00
|
|
|
actions.fetchAllMangoGroups()
|
2021-04-14 23:16:36 -07:00
|
|
|
actions.fetchMangoGroup()
|
|
|
|
}, [actions])
|
|
|
|
|
2021-04-26 12:17:57 -07:00
|
|
|
useInterval(() => {
|
|
|
|
actions.fetchMangoGroup()
|
2021-04-29 08:08:36 -07:00
|
|
|
}, 60 * SECONDS)
|
2021-04-07 08:44:22 -07:00
|
|
|
|
|
|
|
// load all markets for mangoGroup
|
|
|
|
useEffect(() => {
|
|
|
|
Promise.all(
|
|
|
|
marketList.map((mkt) => {
|
|
|
|
return Market.load(connection, mkt.address, {}, mkt.programId)
|
|
|
|
})
|
|
|
|
).then((markets) => {
|
|
|
|
setMangoStore((state) => {
|
2021-04-29 08:08:36 -07:00
|
|
|
state.selectedMarket.current = markets[0]
|
2021-04-07 08:44:22 -07:00
|
|
|
markets.forEach((market) => {
|
|
|
|
state.selectedMangoGroup.markets[market.publicKey.toString()] = market
|
2021-04-29 08:08:36 -07:00
|
|
|
const bidAcctAddress = market['_decoded'].bids.toString()
|
2021-04-07 14:49:37 -07:00
|
|
|
if (!(bidAcctAddress in state.accountInfos)) {
|
|
|
|
state.accountInfos[bidAcctAddress] = null
|
|
|
|
}
|
2021-04-29 08:08:36 -07:00
|
|
|
const askAcctAddress = market['_decoded'].asks.toString()
|
2021-04-07 14:49:37 -07:00
|
|
|
if (!(askAcctAddress in state.accountInfos)) {
|
|
|
|
state.accountInfos[askAcctAddress] = null
|
|
|
|
}
|
2021-04-07 08:44:22 -07:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}, [marketList])
|
|
|
|
|
2021-04-14 23:16:36 -07:00
|
|
|
// hydrate orderbook with all markets in mango group
|
2021-04-07 08:44:22 -07:00
|
|
|
useEffect(() => {
|
|
|
|
const subscriptionIds = Object.entries(marketsForSelectedMangoGroup).map(
|
|
|
|
([, market]) => {
|
|
|
|
let previousBidInfo: AccountInfo<Buffer> | null = null
|
|
|
|
let previousAskInfo: AccountInfo<Buffer> | null = null
|
|
|
|
return [
|
2021-04-20 14:00:45 -07:00
|
|
|
websocketConnection.onAccountChange(
|
2021-04-07 08:44:22 -07:00
|
|
|
// @ts-ignore
|
|
|
|
market._decoded.bids,
|
|
|
|
(info) => {
|
|
|
|
if (
|
|
|
|
!previousBidInfo ||
|
|
|
|
!previousBidInfo.data.equals(info.data) ||
|
|
|
|
previousBidInfo.lamports !== info.lamports
|
|
|
|
) {
|
|
|
|
previousBidInfo = info
|
|
|
|
setMangoStore((state) => {
|
|
|
|
// @ts-ignore
|
|
|
|
const pkString = market._decoded.bids.toString()
|
|
|
|
state.accountInfos[pkString] = previousBidInfo
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
),
|
2021-04-20 14:00:45 -07:00
|
|
|
websocketConnection.onAccountChange(
|
2021-04-07 08:44:22 -07:00
|
|
|
// @ts-ignore
|
|
|
|
market._decoded.asks,
|
|
|
|
(info) => {
|
|
|
|
if (
|
|
|
|
!previousAskInfo ||
|
|
|
|
!previousAskInfo.data.equals(info.data) ||
|
|
|
|
previousAskInfo.lamports !== info.lamports
|
|
|
|
) {
|
|
|
|
previousAskInfo = info
|
|
|
|
setMangoStore((state) => {
|
|
|
|
// @ts-ignore
|
2021-04-07 14:49:37 -07:00
|
|
|
const pkString = market._decoded.asks.toString()
|
2021-04-07 08:44:22 -07:00
|
|
|
state.accountInfos[pkString] = previousAskInfo
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
),
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
console.log('subscription ids', subscriptionIds)
|
2021-04-06 15:11:42 -07:00
|
|
|
|
2021-04-07 08:44:22 -07:00
|
|
|
return () => {
|
|
|
|
for (const id of subscriptionIds.flat()) {
|
2021-04-20 14:00:45 -07:00
|
|
|
websocketConnection.removeAccountChangeListener(id)
|
2021-04-07 08:44:22 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [marketsForSelectedMangoGroup])
|
2021-04-12 21:40:26 -07:00
|
|
|
|
2021-04-14 23:16:36 -07:00
|
|
|
// fetch filled trades for selected market
|
2021-04-12 21:40:26 -07:00
|
|
|
useInterval(() => {
|
|
|
|
async function fetchFills() {
|
2021-04-29 07:38:28 -07:00
|
|
|
const market = useMangoStore.getState().selectedMarket.current
|
2021-04-12 21:40:26 -07:00
|
|
|
if (!market || !connection) {
|
|
|
|
return null
|
|
|
|
}
|
2021-04-15 12:05:48 -07:00
|
|
|
try {
|
|
|
|
const loadedFills = await market.loadFills(connection, 10000)
|
|
|
|
setSerumStore((state) => {
|
|
|
|
state.fills = loadedFills
|
|
|
|
})
|
|
|
|
} catch (err) {
|
|
|
|
console.log('Error fetching fills:', err)
|
|
|
|
}
|
2021-04-13 09:51:42 -07:00
|
|
|
}
|
2021-04-15 12:05:48 -07:00
|
|
|
|
|
|
|
fetchFills()
|
2021-04-12 21:40:26 -07:00
|
|
|
}, _SLOW_REFRESH_INTERVAL)
|
2021-04-06 15:11:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export default useHydrateStore
|