Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enhance quick stats #1706

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
27 changes: 24 additions & 3 deletions src/app/api/stats/route.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import { CoingeckoProvider, CoinGeckoService } from '@indexcoop/analytics-sdk'
import { NextRequest, NextResponse } from 'next/server'

import { fetchTokenMetrics } from '@/lib/utils/api/index-data-provider'
import { fetchCarryCosts } from '@/lib/utils/fetch'

export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const tokenAddress = searchParams.get('address')
const symbol = searchParams.get('symbol')
const base = searchParams.get('base')
const baseCurrency = searchParams.get('baseCurrency')
if (!symbol || !baseCurrency) {
if (!tokenAddress || !symbol || !base || !baseCurrency) {
return NextResponse.json('Bad Request', { status: 400 })
}
try {
const coingeckoService = new CoinGeckoService(
process.env.COINGECKO_API_KEY!,
)
const provider = new CoingeckoProvider(coingeckoService)
const data = await provider.getTokenStats(symbol, baseCurrency)
return NextResponse.json({ ...data })
const data = await provider.getTokenStats(base, baseCurrency)
const carryCosts = await fetchCarryCosts()
const costOfCarry = carryCosts
? carryCosts[symbol.toLowerCase()] ?? null
: null
const metrics = await fetchTokenMetrics({
tokenAddress: tokenAddress,
metrics: ['nav', 'navchange'],
})
return NextResponse.json({
base: { ...data, baseCurrency },
token: {
symbol,
costOfCarry,
nav: metrics?.NetAssetValue ?? 0,
navchange: (metrics?.NavChange24Hr ?? 0) * 100,
},
})
} catch (error) {
return NextResponse.json(error, { status: 500 })
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Disclosure } from '@headlessui/react'
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/20/solid'

import { useLeverageToken } from '@/app/leverage/provider'
import { GasFees } from '@/components/gas-fees'
import { StyledSkeleton } from '@/components/skeleton'

Expand All @@ -26,7 +25,6 @@ function SummaryQuote(props: SummaryQuoteProps) {
}

export function Summary() {
const { stats } = useLeverageToken()
const {
gasFeesEth,
gasFeesUsd,
Expand All @@ -36,7 +34,7 @@ export function Summary() {
ouputAmount,
outputAmountUsd,
shouldShowSummaryDetails,
} = useFormattedLeverageData(stats)
} = useFormattedLeverageData()
if (!shouldShowSummaryDetails && !isFetchingQuote) return null
return (
<Disclosure as='div' className='rounded-xl border border-[#3A6060]'>
Expand Down
10 changes: 6 additions & 4 deletions src/app/leverage/components/leverage-widget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { useDisclosure } from '@chakra-ui/react'
import { useCallback } from 'react'

import { useQuickStats } from '@/app/leverage/components/stats/use-quick-stats'
import { supportedNetworks } from '@/app/leverage/constants'
import { useLeverageToken } from '@/app/leverage/provider'
import { Receive } from '@/components/receive'
Expand Down Expand Up @@ -33,15 +34,15 @@ export function LeverageWidget() {
const { queryParams } = useQueryParams()
const { address } = useWallet()
const {
indexToken,
inputToken,
inputTokenAmount,
inputTokens,
inputValue,
isMinting,
costOfCarry,
leverageType,
market,
outputTokens,
stats,
transactionReview,
onChangeInputTokenAmount,
onSelectInputToken,
Expand All @@ -52,6 +53,7 @@ export function LeverageWidget() {
supportedLeverageTypes,
toggleIsMinting,
} = useLeverageToken()
const { data } = useQuickStats(market, indexToken)

const {
contract,
Expand All @@ -63,7 +65,7 @@ export function LeverageWidget() {
ouputAmount,
outputAmountUsd,
resetData,
} = useFormattedLeverageData(stats)
} = useFormattedLeverageData()

const {
isOpen: isSelectInputTokenOpen,
Expand Down Expand Up @@ -116,7 +118,7 @@ export function LeverageWidget() {
onSelectToken={onOpenSelectOutputToken}
/>
<Summary />
<Fees costOfCarry={costOfCarry} leverageType={leverageType} />
<Fees costOfCarry={data.token.costOfCarry} leverageType={leverageType} />
<SmartTradeButton
contract={contract ?? ''}
hasFetchingError={false}
Expand Down
9 changes: 6 additions & 3 deletions src/app/leverage/components/stats/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import { useLeverageToken } from '@/app/leverage/provider'
import { formatAmount } from '@/lib/utils'

export function QuickStats() {
const { market } = useLeverageToken()
const { data: quickStats, isFetchingQuickStats } = useQuickStats(market)
const { price, change24h, low24h, high24h } = quickStats
const { indexToken, market } = useLeverageToken()
const { data: quickStats, isFetchingQuickStats } = useQuickStats(
market,
indexToken,
)
const { price, change24h, low24h, high24h } = quickStats.base
return (
<div
className='bg-ic-gray-950 flex w-full items-center justify-between rounded-lg'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Image from 'next/image'

import { useQuickStats } from '@/app/leverage/components/stats/use-quick-stats'
import { useLeverageToken } from '@/app/leverage/provider'
import { formatAmount } from '@/lib/utils'

Expand Down Expand Up @@ -107,7 +108,8 @@ export function TokenSelector({ selectedToken }: TokenSelectProps) {
}

export function LeverageSelectorContainer() {
const { indexToken, isFetchingStats, navchange } = useLeverageToken()
const { indexToken, market } = useLeverageToken()
const { data, isFetchingQuickStats } = useQuickStats(market, indexToken)
return (
<div className='border-ic-black xs:justify-end flex h-full w-2/3 items-center gap-8 border-l px-16 py-0'>
{/* <Popover className='flex'>
Expand Down Expand Up @@ -146,10 +148,12 @@ export function LeverageSelectorContainer() {
<TokenSelector selectedToken={indexToken} />
<StatsMetric
className='hidden w-20 sm:flex'
isLoading={isFetchingStats}
isLoading={isFetchingQuickStats}
label='24h Change'
value={`${formatAmount(navchange, 2)}%`}
overrideLabelColor={navchange >= 0 ? 'text-ic-green' : 'text-ic-red'}
value={`${formatAmount(data.token.navchange, 2)}%`}
overrideLabelColor={
data.token.navchange >= 0 ? 'text-ic-green' : 'text-ic-red'
}
/>
</div>
)
Expand Down
111 changes: 80 additions & 31 deletions src/app/leverage/components/stats/use-quick-stats.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,95 @@
import { useQuery } from '@tanstack/react-query'
import { QueryFunctionContext, useQuery } from '@tanstack/react-query'

import { formatAmount, formatDollarAmount } from '@/lib/utils'

interface QuickStats {
symbol: string
price: string
change24h: number
low24h: string
high24h: string
base: {
symbol: string
price: string
change24h: number
low24h: string
high24h: string
}
token: {
symbol: string
costOfCarry: number
nav: number
navchange: number
}
}

interface QuickStatsApiResponse {
symbol: string
price: number
change24h: number
low24h: number
high24h: number
base: {
symbol: string
price: number
change24h: number
low24h: number
high24h: number
}
token: {
symbol: string
costOfCarry: number
nav: number
navchange: number
}
}

type QuickStatsQueryKey = [
string,
{ address: string | undefined; symbol: string; market: string },
]

function formatStatsAmount(amount: number, baseCurrency: string): string {
if (baseCurrency === 'btc') return `${formatAmount(amount, 4)} BTC`
if (baseCurrency === 'eth') return `${formatAmount(amount, 4)} ETH`
return formatDollarAmount(amount, true, 2)
}

export function useQuickStats(market: string) {
async function fetchStats(): Promise<QuickStats> {
export function useQuickStats(
market: string,
indexToken: { address: string | undefined; symbol: string },
) {
async function fetchStats(
context: QueryFunctionContext<QuickStatsQueryKey>,
): Promise<QuickStats> {
const [, { address, symbol, market }] = context.queryKey
const m = market.split(' / ')
const symbol = m[0]
const baseToken = m[0]
const baseCurrency = m[1].toLowerCase()
try {
const response = await fetch(
`/api/stats?symbol=${symbol}&baseCurrency=${baseCurrency}`,
`/api/stats?address=${address}&symbol=${symbol}&base=${baseToken}&baseCurrency=${baseCurrency}`,
{
method: 'GET',
},
)
const json: QuickStatsApiResponse = await response.json()
const { base, token }: QuickStatsApiResponse = await response.json()
return {
symbol: json.symbol,
price: formatStatsAmount(json.price, baseCurrency),
change24h: json.change24h,
low24h: formatStatsAmount(json.low24h, baseCurrency),
high24h: formatStatsAmount(json.high24h, baseCurrency),
base: {
symbol: base.symbol,
price: formatStatsAmount(base.price, baseCurrency),
change24h: base.change24h,
low24h: formatStatsAmount(base.low24h, baseCurrency),
high24h: formatStatsAmount(base.high24h, baseCurrency),
},
token: { ...token },
}
} catch (error) {
console.warn('Error fetching quick stats:', error)
return {
symbol,
price: '',
change24h: 0,
low24h: '',
high24h: '',
base: {
symbol: baseToken,
price: '',
change24h: 0,
low24h: '',
high24h: '',
},
token: {
symbol: '',
costOfCarry: 0,
nav: 0,
navchange: 0,
},
}
}
}
Expand All @@ -60,19 +98,30 @@ export function useQuickStats(market: string) {
queryKey: [
'fetch-quick-stats',
{
symbol: indexToken.symbol,
address: indexToken.address,
market,
},
],
queryFn: fetchStats,
enabled: !!indexToken.address,
})

return {
data: data ?? {
symbol: '',
price: '',
change24h: 0,
low24h: '',
high24h: '',
base: {
symbol: '',
price: '',
change24h: 0,
low24h: '',
high24h: '',
},
token: {
symbol: '',
costOfCarry: 0,
nav: 0,
navchange: 0,
},
},
isFetchingQuickStats: isFetching,
}
Expand Down
9 changes: 7 additions & 2 deletions src/app/leverage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Suspense, useEffect, useState } from 'react'

import { ChartTabs } from '@/app/leverage/components/chart-tabs'
import { QuickStats } from '@/app/leverage/components/stats/index'
import { useQuickStats } from '@/app/leverage/components/stats/use-quick-stats'
import TradingViewWidget from '@/app/leverage/components/trading-view-widget'
import { useLeverageToken } from '@/app/leverage/provider'
import { ChartTab } from '@/app/leverage/types'
Expand All @@ -18,7 +19,11 @@ import { YourTokens } from './components/your-tokens'
const surveyTracking = { utm_source: 'app' }

export default function Page() {
const { indexToken, nav } = useLeverageToken()
const { indexToken, market } = useLeverageToken()
const { data } = useQuickStats(market, {
address: indexToken.address!,
symbol: indexToken.symbol,
})
const [currentTab, setCurrentTab] = useState<ChartTab>('indexcoop-chart')
const { colorMode, toggleColorMode } = useColorMode()

Expand Down Expand Up @@ -53,7 +58,7 @@ export default function Page() {
<PriceChart
indexToken={indexToken}
indexTokenAddress={indexToken.address ?? ''}
nav={nav}
nav={data.token.nav}
/>
) : (
<>
Expand Down
Loading
Loading