Merge pull request #352 from blockworks-foundation/saml33/birdeye-change
use birdeye for change values
This commit is contained in:
commit
300c8fcc00
|
@ -1,5 +1,5 @@
|
|||
import Decimal from 'decimal.js'
|
||||
import { BirdeyePriceResponse } from 'hooks/useBirdeyeMarketPrices'
|
||||
import { BirdeyePriceResponse } from 'types'
|
||||
import { DAILY_SECONDS } from 'utils/constants'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
|
|
@ -33,10 +33,7 @@ const PerpMarketsTable = () => {
|
|||
const showTableView = width ? width > breakpoints.md : false
|
||||
const rate = usePerpFundingRate()
|
||||
const router = useRouter()
|
||||
const { perpMarketsWithData, isLoading, isFetching } =
|
||||
useListedMarketsWithMarketData()
|
||||
|
||||
const loadingMarketData = isLoading || isFetching
|
||||
const { perpMarketsWithData, isLoading } = useListedMarketsWithMarketData()
|
||||
|
||||
return (
|
||||
<ContentBox hideBorder hidePadding>
|
||||
|
@ -126,8 +123,8 @@ const PerpMarketsTable = () => {
|
|||
</div>
|
||||
</Td>
|
||||
<Td>
|
||||
{!loadingMarketData ? (
|
||||
priceHistory && priceHistory.length ? (
|
||||
{!isLoading ? (
|
||||
priceHistory && priceHistory?.length ? (
|
||||
<div className="h-10 w-24">
|
||||
<SimpleAreaChart
|
||||
color={
|
||||
|
@ -236,7 +233,7 @@ const PerpMarketsTable = () => {
|
|||
return (
|
||||
<MobilePerpMarketItem
|
||||
key={market.publicKey.toString()}
|
||||
loadingMarketData={loadingMarketData}
|
||||
loadingMarketData={isLoading}
|
||||
market={market}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -98,10 +98,7 @@ const RecentGainersLosers = () => {
|
|||
for (const token of banksWithMarketData) {
|
||||
const volume = token.market?.marketData?.quote_volume_24h || 0
|
||||
if (token.market?.quoteTokenIndex === 0 && volume > 0) {
|
||||
const pastPrice = token.market?.marketData?.price_24h
|
||||
const change = pastPrice
|
||||
? ((token.bank.uiPrice - pastPrice) / pastPrice) * 100
|
||||
: 0
|
||||
const change = token.market?.rollingChange || 0
|
||||
tradeableAssets.push({ bank: token.bank, change, type: 'spot' })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import Input from '@components/forms/Input'
|
|||
import EmptyState from '@components/nftMarket/EmptyState'
|
||||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import useBanks from 'hooks/useBanks'
|
||||
import SheenLoader from '@components/shared/SheenLoader'
|
||||
|
||||
export type BankWithMarketData = {
|
||||
bank: Bank
|
||||
|
@ -91,7 +92,8 @@ const Spot = () => {
|
|||
const { t } = useTranslation(['common', 'explore', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const { banks } = useBanks()
|
||||
const { serumMarketsWithData } = useListedMarketsWithMarketData()
|
||||
const { serumMarketsWithData, isLoading: loadingMarketsData } =
|
||||
useListedMarketsWithMarketData()
|
||||
const [sortByKey, setSortByKey] = useState<AllowedKeys>('quote_volume_24h')
|
||||
const [search, setSearch] = useState('')
|
||||
const [showTableView, setShowTableView] = useState(true)
|
||||
|
@ -169,7 +171,15 @@ const Spot = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{sortedTokensToShow.length ? (
|
||||
{loadingMarketsData ? (
|
||||
<div className="mx-4 my-6 space-y-1 md:mx-6">
|
||||
{[...Array(4)].map((x, i) => (
|
||||
<SheenLoader className="flex flex-1" key={i}>
|
||||
<div className="h-16 w-full bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
))}
|
||||
</div>
|
||||
) : sortedTokensToShow.length ? (
|
||||
showTableView ? (
|
||||
<div className="mt-6 border-t border-th-bkg-3">
|
||||
<SpotTable tokens={sortedTokensToShow} />
|
||||
|
|
|
@ -14,7 +14,6 @@ import Tooltip from '@components/shared/Tooltip'
|
|||
import SimpleAreaChart from '@components/shared/SimpleAreaChart'
|
||||
import { COLORS } from 'styles/colors'
|
||||
import useThemeWrapper from 'hooks/useThemeWrapper'
|
||||
import dayjs from 'dayjs'
|
||||
import TokenReduceOnlyDesc from '@components/shared/TokenReduceOnlyDesc'
|
||||
import CollateralWeightDisplay from '@components/shared/CollateralWeightDisplay'
|
||||
|
||||
|
@ -38,18 +37,15 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
).mul(bank.uiPrice)
|
||||
const depositRate = bank.getDepositRateUi()
|
||||
const borrowRate = bank.getBorrowRateUi()
|
||||
const pastPrice = token.market?.marketData?.price_24h
|
||||
const volume = token.market?.marketData?.quote_volume_24h || 0
|
||||
const change =
|
||||
volume > 0 && pastPrice
|
||||
? ((bank.uiPrice - pastPrice) / pastPrice) * 100
|
||||
: 0
|
||||
const chartData = token?.market?.priceHistory?.length
|
||||
? token.market.priceHistory
|
||||
?.sort((a, b) => a.time - b.time)
|
||||
.concat([{ price: bank.uiPrice, time: Date.now() }])
|
||||
: []
|
||||
|
||||
const chartData =
|
||||
token.market?.marketData?.price_history
|
||||
?.sort((a, b) => a.time.localeCompare(b.time))
|
||||
.concat([{ price: bank.uiPrice, time: dayjs().toISOString() }]) ||
|
||||
[]
|
||||
const volume = token.market?.marketData?.quote_volume_24h || 0
|
||||
|
||||
const change = token.market?.rollingChange || 0
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -66,6 +62,7 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
<TokenReduceOnlyDesc bank={bank} />
|
||||
</span>
|
||||
</h3>
|
||||
{bank.uiPrice ? (
|
||||
<div className="flex items-center space-x-3">
|
||||
<span className="font-mono">
|
||||
<FormatNumericValue value={bank.uiPrice} isUsd />
|
||||
|
@ -74,6 +71,7 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
<Change change={change} suffix="%" />
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{chartData.length ? (
|
||||
|
@ -98,11 +96,9 @@ const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
<p className="font-mono text-th-fgd-2">
|
||||
{!token.market ? (
|
||||
'–'
|
||||
) : token.market?.marketData?.quote_volume_24h ? (
|
||||
) : volume ? (
|
||||
<span>
|
||||
{numberCompacter.format(
|
||||
token.market.marketData.quote_volume_24h,
|
||||
)}{' '}
|
||||
{numberCompacter.format(volume)}{' '}
|
||||
<span className="font-body text-th-fgd-4">USDC</span>
|
||||
</span>
|
||||
) : (
|
||||
|
|
|
@ -30,7 +30,6 @@ import BankAmountWithValue from '@components/shared/BankAmountWithValue'
|
|||
import { BankWithMarketData } from './Spot'
|
||||
import { SerumMarketWithMarketData } from 'hooks/useListedMarketsWithMarketData'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import dayjs from 'dayjs'
|
||||
import TableTokenName from '@components/shared/TableTokenName'
|
||||
import { LinkButton } from '@components/shared/Button'
|
||||
import { formatTokenSymbol } from 'utils/tokens'
|
||||
|
@ -48,7 +47,7 @@ type TableData = {
|
|||
price: number
|
||||
priceHistory: {
|
||||
price: number
|
||||
time: string
|
||||
time: number
|
||||
}[]
|
||||
volume: number
|
||||
isUp: boolean
|
||||
|
@ -69,17 +68,15 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
const baseBank = token.bank
|
||||
const price = baseBank.uiPrice
|
||||
|
||||
const pastPrice = token.market?.marketData?.price_24h
|
||||
|
||||
const priceHistory =
|
||||
token.market?.marketData?.price_history
|
||||
?.sort((a, b) => a.time.localeCompare(b.time))
|
||||
.concat([{ price: price, time: dayjs().toISOString() }]) || []
|
||||
const priceHistory = token?.market?.priceHistory?.length
|
||||
? token.market.priceHistory
|
||||
?.sort((a, b) => a.time - b.time)
|
||||
.concat([{ price: price, time: Date.now() }])
|
||||
: []
|
||||
|
||||
const volume = token.market?.marketData?.quote_volume_24h || 0
|
||||
|
||||
const change =
|
||||
volume > 0 && pastPrice ? ((price - pastPrice) / pastPrice) * 100 : 0
|
||||
const change = token.market?.rollingChange || 0
|
||||
|
||||
const tokenName = baseBank.name
|
||||
|
||||
|
@ -272,7 +269,7 @@ const SpotTable = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|||
</Td>
|
||||
<Td>
|
||||
<div className="flex flex-col items-end">
|
||||
{market ? (
|
||||
{market && price ? (
|
||||
<Change change={change} suffix="%" />
|
||||
) : (
|
||||
<span>–</span>
|
||||
|
|
|
@ -13,7 +13,7 @@ const MarketChange = ({
|
|||
market: PerpMarket | Serum3Market | undefined
|
||||
size?: 'small'
|
||||
}) => {
|
||||
const { perpMarketsWithData, serumMarketsWithData, isLoading, isFetching } =
|
||||
const { perpMarketsWithData, serumMarketsWithData, isLoading } =
|
||||
useListedMarketsWithMarketData()
|
||||
|
||||
const change = useMemo(() => {
|
||||
|
@ -23,18 +23,16 @@ const MarketChange = ({
|
|||
const perpMarket = perpMarketsWithData.find(
|
||||
(m) => m.name.toLowerCase() === market.name.toLowerCase(),
|
||||
)
|
||||
return perpMarket ? perpMarket.rollingChange : 0
|
||||
return perpMarket?.rollingChange ? perpMarket.rollingChange : 0
|
||||
} else {
|
||||
const spotMarket = serumMarketsWithData.find(
|
||||
(m) => m.name.toLowerCase() === market.name.toLowerCase(),
|
||||
)
|
||||
return spotMarket ? spotMarket.rollingChange : 0
|
||||
return spotMarket?.rollingChange ? spotMarket.rollingChange : 0
|
||||
}
|
||||
}, [perpMarketsWithData, serumMarketsWithData])
|
||||
|
||||
const loading = isLoading || isFetching
|
||||
|
||||
return loading ? (
|
||||
return isLoading ? (
|
||||
<SheenLoader className="mt-0.5">
|
||||
<div className="h-3.5 w-12 bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
|
|
|
@ -6,13 +6,13 @@ import { useQuery } from '@tanstack/react-query'
|
|||
import { makeApiRequest } from 'apis/birdeye/helpers'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { BirdeyePriceResponse } from 'hooks/useBirdeyeMarketPrices'
|
||||
import parse from 'html-react-parser'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { DAILY_SECONDS } from 'utils/constants'
|
||||
import DetailedAreaOrBarChart from '@components/shared/DetailedAreaOrBarChart'
|
||||
import { countLeadingZeros, formatCurrencyValue } from 'utils/numbers'
|
||||
import { BirdeyePriceResponse } from 'types'
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
const DEFAULT_COINGECKO_VALUES = {
|
||||
|
|
|
@ -55,7 +55,7 @@ const MarketSelectDropdown = () => {
|
|||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { group } = useMangoGroup()
|
||||
const [spotBaseFilter, setSpotBaseFilter] = useState('All')
|
||||
const { perpMarketsWithData, serumMarketsWithData, isLoading, isFetching } =
|
||||
const { perpMarketsWithData, serumMarketsWithData, isLoading } =
|
||||
useListedMarketsWithMarketData()
|
||||
const { isDesktop } = useViewport()
|
||||
const focusRef = useRef<HTMLInputElement>(null)
|
||||
|
@ -130,8 +130,6 @@ const MarketSelectDropdown = () => {
|
|||
}
|
||||
}, [focusRef, isDesktop, isOpen, spotOrPerp])
|
||||
|
||||
const loadingMarketData = isLoading || isFetching
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
{({ open, close }) => (
|
||||
|
@ -269,7 +267,7 @@ const MarketSelectDropdown = () => {
|
|||
<MarketChange market={m} size="small" />
|
||||
</div>
|
||||
<div className="col-span-1 hidden sm:flex sm:justify-end">
|
||||
{loadingMarketData ? (
|
||||
{isLoading ? (
|
||||
<SheenLoader className="mt-0.5">
|
||||
<div className="h-3.5 w-12 bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
|
@ -446,7 +444,7 @@ const MarketSelectDropdown = () => {
|
|||
<MarketChange market={m} size="small" />
|
||||
</div>
|
||||
<div className="col-span-1 hidden sm:flex sm:justify-end">
|
||||
{loadingMarketData ? (
|
||||
{isLoading ? (
|
||||
<SheenLoader className="mt-0.5">
|
||||
<div className="h-3.5 w-12 bg-th-bkg-2" />
|
||||
</SheenLoader>
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
import { Group, Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { makeApiRequest } from 'apis/birdeye/helpers'
|
||||
import useMangoGroup from './useMangoGroup'
|
||||
import { DAILY_SECONDS } from 'utils/constants'
|
||||
|
||||
const fetchBirdeye24hrPrices = async (
|
||||
group: Group | undefined,
|
||||
spotMarkets: Serum3Market[],
|
||||
) => {
|
||||
if (!group) return []
|
||||
|
||||
try {
|
||||
const queryEnd = Math.floor(Date.now() / 1000)
|
||||
const queryStart = queryEnd - DAILY_SECONDS
|
||||
|
||||
// collect unique quote tokens
|
||||
const uniqueQuoteTokens = Array.from(
|
||||
new Set(
|
||||
spotMarkets.map((market) => {
|
||||
const quoteBank = group.getFirstBankByTokenIndex(
|
||||
market.quoteTokenIndex,
|
||||
)
|
||||
return quoteBank?.mint
|
||||
}),
|
||||
),
|
||||
).filter(Boolean) // remove any undefined values
|
||||
|
||||
// fetch responses for unique quote tokens
|
||||
const quoteResponses = await Promise.all(
|
||||
uniqueQuoteTokens.map(async (quoteToken) => {
|
||||
const quoteQuery = `defi/history_price?address=${quoteToken}&address_type=token&type=1H&time_from=${queryStart}&time_to=${queryEnd}`
|
||||
const quoteResponse = await makeApiRequest(quoteQuery)
|
||||
return {
|
||||
quoteToken,
|
||||
items: quoteResponse?.data?.items?.length
|
||||
? quoteResponse.data.items
|
||||
: [],
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
// create a map for quick access to quote items based on quoteToken
|
||||
const quoteItemsMap = new Map(
|
||||
quoteResponses.map((response) => [response.quoteToken, response.items]),
|
||||
)
|
||||
|
||||
// fetch base responses and match them with quote items
|
||||
const promises = spotMarkets.map(async (market) => {
|
||||
const baseBank = group.getFirstBankByTokenIndex(market.baseTokenIndex)
|
||||
const quoteBank = group.getFirstBankByTokenIndex(market.quoteTokenIndex)
|
||||
|
||||
const baseQuery = `defi/history_price?address=${baseBank?.mint}&address_type=token&type=1H&time_from=${queryStart}&time_to=${queryEnd}`
|
||||
|
||||
const baseResponse = await makeApiRequest(baseQuery)
|
||||
|
||||
return {
|
||||
base: baseResponse?.data?.items?.length ? baseResponse.data.items : [],
|
||||
quote: quoteItemsMap.get(quoteBank?.mint) || [],
|
||||
marketIndex: market.marketIndex,
|
||||
}
|
||||
})
|
||||
|
||||
const responses = await Promise.all(promises)
|
||||
|
||||
return responses
|
||||
} catch (e) {
|
||||
console.error('error fetching 24-hour price data from birdeye', e)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export const useBirdeye24hrPrices = () => {
|
||||
const spotMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const { group } = useMangoGroup()
|
||||
return useQuery(
|
||||
['birdeye-daily-prices'],
|
||||
() => fetchBirdeye24hrPrices(group, spotMarkets),
|
||||
{
|
||||
cacheTime: 1000 * 60 * 15,
|
||||
staleTime: 1000 * 60 * 10,
|
||||
retry: 3,
|
||||
enabled: !!(group && spotMarkets?.length),
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import { Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { makeApiRequest } from 'apis/birdeye/helpers'
|
||||
import { DAILY_SECONDS } from 'utils/constants'
|
||||
|
||||
export interface BirdeyePriceResponse {
|
||||
address: string
|
||||
unixTime: number
|
||||
value: number
|
||||
}
|
||||
|
||||
const fetchBirdeyePrices = async (
|
||||
spotMarkets: Serum3Market[],
|
||||
): Promise<{ data: BirdeyePriceResponse[]; mint: string }[]> => {
|
||||
const mints = spotMarkets.map((market) =>
|
||||
market.serumMarketExternal.toString(),
|
||||
)
|
||||
|
||||
const promises = []
|
||||
const queryEnd = Math.floor(Date.now() / 1000)
|
||||
const queryStart = queryEnd - DAILY_SECONDS
|
||||
for (const mint of mints) {
|
||||
const query = `defi/history_price?address=${mint}&address_type=pair&type=30m&time_from=${queryStart}&time_to=${queryEnd}`
|
||||
promises.push(makeApiRequest(query))
|
||||
}
|
||||
|
||||
const responses = await Promise.all(promises)
|
||||
if (responses?.length) {
|
||||
return responses.map((res) => ({
|
||||
data: res.data.items,
|
||||
mint: res.data.items[0]?.address,
|
||||
}))
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export const useBirdeyeMarketPrices = () => {
|
||||
const spotMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const res = useQuery(
|
||||
['birdeye-market-prices'],
|
||||
() => fetchBirdeyePrices(spotMarkets),
|
||||
{
|
||||
cacheTime: 1000 * 60 * 15,
|
||||
staleTime: 1000 * 60 * 10,
|
||||
retry: 3,
|
||||
enabled: !!spotMarkets?.length,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
isFetching: res?.isFetching,
|
||||
isLoading: res?.isLoading,
|
||||
data: res?.data || [],
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import useMarketsData from './useMarketsData'
|
|||
import { useMemo } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4'
|
||||
import { useBirdeye24hrPrices } from './useBirdeye24hrPrices'
|
||||
|
||||
type ApiData = {
|
||||
marketData: MarketsDataItem | undefined
|
||||
|
@ -10,6 +11,7 @@ type ApiData = {
|
|||
|
||||
type MarketRollingChange = {
|
||||
rollingChange: number | undefined
|
||||
priceHistory: Array<{ price: number; time: number }>
|
||||
}
|
||||
|
||||
export type SerumMarketWithMarketData = Serum3Market &
|
||||
|
@ -21,7 +23,12 @@ export type PerpMarketWithMarketData = PerpMarket &
|
|||
MarketRollingChange
|
||||
|
||||
export default function useListedMarketsWithMarketData() {
|
||||
const { data: marketsData, isLoading, isFetching } = useMarketsData()
|
||||
const { data: marketsData, isInitialLoading: loadingMarketsData } =
|
||||
useMarketsData()
|
||||
const {
|
||||
data: birdeyeSpotDailyPrices,
|
||||
isInitialLoading: loadingBirdeyeSpotDailyPrices,
|
||||
} = useBirdeye24hrPrices()
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const perpMarkets = mangoStore((s) => s.perpMarkets)
|
||||
|
||||
|
@ -62,27 +69,43 @@ export default function useListedMarketsWithMarketData() {
|
|||
if (!serumMarkets || !serumMarkets.length) return []
|
||||
const allSpotMarkets: SerumMarketWithMarketData[] =
|
||||
serumMarkets as SerumMarketWithMarketData[]
|
||||
if (spotData) {
|
||||
if (spotData && birdeyeSpotDailyPrices?.length) {
|
||||
for (const market of allSpotMarkets) {
|
||||
const spotEntries = Object.entries(spotData).find(
|
||||
(e) => e[0].toLowerCase() === market.name.toLowerCase(),
|
||||
)
|
||||
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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculate price change
|
||||
const pastPrice = spotEntries ? spotEntries[1][0]?.price_24h : 0
|
||||
const dailyVolume = spotEntries
|
||||
? spotEntries[1][0]?.quote_volume_24h
|
||||
: 0
|
||||
const currentPrice = currentPrices[market.name]
|
||||
const change =
|
||||
dailyVolume > 0 ? ((currentPrice - pastPrice) / pastPrice) * 100 : 0
|
||||
const change = currentPrice
|
||||
? ((currentPrice - pastPrice) / pastPrice) * 100
|
||||
: 0
|
||||
|
||||
market.rollingChange = change
|
||||
market.priceHistory = priceHistory
|
||||
market.marketData = spotEntries ? spotEntries[1][0] : undefined
|
||||
}
|
||||
}
|
||||
return [...allSpotMarkets].sort((a, b) => a.name.localeCompare(b.name))
|
||||
}, [spotData, serumMarkets])
|
||||
}, [currentPrices, birdeyeSpotDailyPrices, spotData, serumMarkets])
|
||||
|
||||
const perpMarketsWithData = useMemo(() => {
|
||||
if (!perpMarkets || !perpMarkets.length) return []
|
||||
|
@ -111,5 +134,7 @@ export default function useListedMarketsWithMarketData() {
|
|||
)
|
||||
}, [perpData, perpMarkets])
|
||||
|
||||
return { perpMarketsWithData, serumMarketsWithData, isLoading, isFetching }
|
||||
const isLoading = loadingMarketsData || loadingBirdeyeSpotDailyPrices
|
||||
|
||||
return { perpMarketsWithData, serumMarketsWithData, isLoading }
|
||||
}
|
||||
|
|
|
@ -498,6 +498,12 @@ export function isMangoError(error: unknown): error is MangoError {
|
|||
)
|
||||
}
|
||||
|
||||
export interface BirdeyePriceResponse {
|
||||
address: string
|
||||
unixTime: number
|
||||
value: number
|
||||
}
|
||||
|
||||
export type MarketData = { [key: string]: MarketsDataItem[] }
|
||||
|
||||
export type MarketsDataItem = {
|
||||
|
|
Loading…
Reference in New Issue