2023-07-24 05:14:45 -07:00
|
|
|
import { MarketData, MarketsDataItem } from 'types'
|
|
|
|
import useMarketsData from './useMarketsData'
|
|
|
|
import { useMemo } from 'react'
|
|
|
|
import mangoStore from '@store/mangoStore'
|
|
|
|
import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4'
|
2023-12-17 20:39:47 -08:00
|
|
|
import { useBirdeye24hrPrices } from './useBirdeye24hrPrices'
|
2023-07-24 05:14:45 -07:00
|
|
|
|
|
|
|
type ApiData = {
|
|
|
|
marketData: MarketsDataItem | undefined
|
|
|
|
}
|
|
|
|
|
2023-09-08 15:01:08 -07:00
|
|
|
type MarketRollingChange = {
|
|
|
|
rollingChange: number | undefined
|
2023-12-17 20:39:47 -08:00
|
|
|
priceHistory: Array<{ price: number; time: number }>
|
2023-09-08 15:01:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export type SerumMarketWithMarketData = Serum3Market &
|
|
|
|
ApiData &
|
|
|
|
MarketRollingChange
|
2023-07-24 05:14:45 -07:00
|
|
|
|
2023-09-08 15:01:08 -07:00
|
|
|
export type PerpMarketWithMarketData = PerpMarket &
|
|
|
|
ApiData &
|
|
|
|
MarketRollingChange
|
2023-07-24 05:14:45 -07:00
|
|
|
|
|
|
|
export default function useListedMarketsWithMarketData() {
|
2023-12-17 20:39:47 -08:00
|
|
|
const { data: marketsData, isInitialLoading: loadingMarketsData } =
|
|
|
|
useMarketsData()
|
|
|
|
const {
|
|
|
|
data: birdeyeSpotDailyPrices,
|
|
|
|
isInitialLoading: loadingBirdeyeSpotDailyPrices,
|
|
|
|
} = useBirdeye24hrPrices()
|
2023-07-24 05:14:45 -07:00
|
|
|
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
|
|
|
const perpMarkets = mangoStore((s) => s.perpMarkets)
|
|
|
|
|
|
|
|
const perpData: MarketData = useMemo(() => {
|
|
|
|
if (!marketsData) return []
|
|
|
|
return marketsData?.perpData || []
|
|
|
|
}, [marketsData])
|
|
|
|
|
|
|
|
const spotData: MarketData = useMemo(() => {
|
|
|
|
if (!marketsData) return []
|
|
|
|
return marketsData?.spotData || []
|
|
|
|
}, [marketsData])
|
|
|
|
|
2023-09-08 15:01:08 -07:00
|
|
|
const currentPrices = useMemo(() => {
|
2023-11-16 07:35:51 -08:00
|
|
|
const prices: { [key: string]: number } = {}
|
2023-09-08 15:01:08 -07:00
|
|
|
const group = mangoStore.getState().group
|
|
|
|
serumMarkets.forEach((market) => {
|
|
|
|
if (!group || !market || market instanceof PerpMarket) {
|
|
|
|
prices[market.name] = 0
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const baseBank = group.getFirstBankByTokenIndex(market.baseTokenIndex)
|
|
|
|
const quoteBank = group.getFirstBankByTokenIndex(market.quoteTokenIndex)
|
|
|
|
if (!baseBank || !quoteBank) {
|
|
|
|
prices[market.name] = 0
|
|
|
|
return
|
|
|
|
}
|
|
|
|
prices[market.name] = baseBank.uiPrice / quoteBank.uiPrice
|
|
|
|
})
|
|
|
|
|
|
|
|
perpMarkets.forEach((market) => {
|
|
|
|
prices[market.name] = market.uiPrice
|
|
|
|
})
|
|
|
|
return prices
|
|
|
|
}, [serumMarkets, perpMarkets])
|
|
|
|
|
2023-07-24 05:14:45 -07:00
|
|
|
const serumMarketsWithData = useMemo(() => {
|
|
|
|
if (!serumMarkets || !serumMarkets.length) return []
|
2024-02-06 17:39:36 -08:00
|
|
|
const group = mangoStore.getState().group
|
2023-07-24 05:14:45 -07:00
|
|
|
const allSpotMarkets: SerumMarketWithMarketData[] =
|
|
|
|
serumMarkets as SerumMarketWithMarketData[]
|
2023-12-17 20:39:47 -08:00
|
|
|
if (spotData && birdeyeSpotDailyPrices?.length) {
|
2023-07-24 05:14:45 -07:00
|
|
|
for (const market of allSpotMarkets) {
|
|
|
|
const spotEntries = Object.entries(spotData).find(
|
|
|
|
(e) => e[0].toLowerCase() === market.name.toLowerCase(),
|
|
|
|
)
|
2024-02-06 17:39:36 -08:00
|
|
|
const marketData = spotEntries
|
|
|
|
? spotEntries[1][0]
|
|
|
|
: ({} as MarketsDataItem)
|
|
|
|
const quoteBankPrice = group?.getFirstBankByTokenIndex(
|
|
|
|
market.quoteTokenIndex,
|
|
|
|
)?.uiPrice
|
|
|
|
marketData.notionalQuoteVolume = marketData?.quote_volume_24h
|
|
|
|
? marketData?.quote_volume_24h * (quoteBankPrice || 1)
|
|
|
|
: 0
|
2023-12-17 20:39:47 -08:00
|
|
|
const birdeyePrices = birdeyeSpotDailyPrices.find(
|
|
|
|
(prices) => prices.marketIndex === market.marketIndex,
|
|
|
|
)
|
|
|
|
const priceHistory = []
|
|
|
|
let pastPrice = 0
|
|
|
|
if (birdeyePrices?.base?.length && birdeyePrices?.quote?.length) {
|
|
|
|
pastPrice =
|
|
|
|
birdeyePrices.base[0]?.value / birdeyePrices.quote[0]?.value
|
|
|
|
for (let i = 0; i < birdeyePrices.base.length; i++) {
|
|
|
|
const base = birdeyePrices.base[i]
|
|
|
|
const quote = birdeyePrices.quote[i]
|
|
|
|
if (base.unixTime === quote?.unixTime && quote?.value) {
|
|
|
|
const price = base.value / quote.value
|
|
|
|
const time = base.unixTime
|
|
|
|
priceHistory.push({ price, time })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-08 15:01:08 -07:00
|
|
|
|
|
|
|
// calculate price change
|
|
|
|
const currentPrice = currentPrices[market.name]
|
2023-12-18 20:10:21 -08:00
|
|
|
const change = currentPrice
|
|
|
|
? ((currentPrice - pastPrice) / pastPrice) * 100
|
|
|
|
: 0
|
2023-09-08 15:01:08 -07:00
|
|
|
market.rollingChange = change
|
2023-12-17 20:39:47 -08:00
|
|
|
market.priceHistory = priceHistory
|
2024-02-06 17:39:36 -08:00
|
|
|
market.marketData = marketData
|
2023-07-24 05:14:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return [...allSpotMarkets].sort((a, b) => a.name.localeCompare(b.name))
|
2023-12-17 20:39:47 -08:00
|
|
|
}, [currentPrices, birdeyeSpotDailyPrices, spotData, serumMarkets])
|
2023-07-24 05:14:45 -07:00
|
|
|
|
|
|
|
const perpMarketsWithData = useMemo(() => {
|
|
|
|
if (!perpMarkets || !perpMarkets.length) return []
|
|
|
|
const allPerpMarkets: PerpMarketWithMarketData[] =
|
|
|
|
perpMarkets as PerpMarketWithMarketData[]
|
|
|
|
if (perpData) {
|
|
|
|
for (const market of allPerpMarkets) {
|
|
|
|
const perpEntries = Object.entries(perpData).find(
|
|
|
|
(e) => e[0].toLowerCase() === market.name.toLowerCase(),
|
|
|
|
)
|
2023-09-08 15:01:08 -07:00
|
|
|
const pastPrice = perpEntries ? perpEntries[1][0]?.price_24h : 0
|
|
|
|
const currentPrice = currentPrices[market.name]
|
|
|
|
|
2023-07-24 05:14:45 -07:00
|
|
|
market.marketData = perpEntries ? perpEntries[1][0] : undefined
|
2023-09-08 15:01:08 -07:00
|
|
|
market.rollingChange = ((currentPrice - pastPrice) / pastPrice) * 100
|
2023-07-24 05:14:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return allPerpMarkets
|
|
|
|
.filter(
|
|
|
|
(p) =>
|
|
|
|
p.publicKey.toString() !==
|
|
|
|
'9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw',
|
|
|
|
)
|
|
|
|
.sort((a, b) =>
|
|
|
|
a.oracleLastUpdatedSlot == 0 ? -1 : a.name.localeCompare(b.name),
|
|
|
|
)
|
2024-02-06 17:39:36 -08:00
|
|
|
}, [currentPrices, perpData, perpMarkets])
|
2023-07-24 05:14:45 -07:00
|
|
|
|
2023-12-17 20:39:47 -08:00
|
|
|
const isLoading = loadingMarketsData || loadingBirdeyeSpotDailyPrices
|
|
|
|
|
|
|
|
return { perpMarketsWithData, serumMarketsWithData, isLoading }
|
2023-07-24 05:14:45 -07:00
|
|
|
}
|