Skip to content

refactor: token query #1154

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

Merged
merged 22 commits into from
Jul 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4989635
refactor: move token queries to ui-kit
0xAlunara Jul 11, 2025
7141a82
refactor: use either curve api or llama api for usd rates
0xAlunara Jul 11, 2025
f293b97
refactor: replace zustand store with token-usd-rate query for loan app
0xAlunara Jul 11, 2025
89904ca
refactor: replace zustand store with token-usd-rate query for dao app
0xAlunara Jul 11, 2025
fb14671
refactor: replace zustand store with token-usd-rate query for dex app
0xAlunara Jul 11, 2025
67c0c85
refactor: use constant to aovid mismatches if it ever changes
0xAlunara Jul 11, 2025
6ed648a
refactor: extract isTokenUsdRateQuery
0xAlunara Jul 11, 2025
d0f9114
refactor: create record using Object.fromEntries
0xAlunara Jul 11, 2025
8032d9e
fix: make useAllTokenUsdRates reactive and avoid unnecessary re-renders
0xAlunara Jul 11, 2025
281e4c5
fix: remove useless token price invalidation when switching networks
0xAlunara Jul 12, 2025
c2db190
refactor: use ethAddress constant from viem
0xAlunara Jul 12, 2025
2e6b4e1
refactor: use existing rootkey for token query
0xAlunara Jul 12, 2025
94f68a7
refactor: create token extraction function for query keys and shorten…
0xAlunara Jul 12, 2025
f4f322d
refactor: simplify query combination typing
0xAlunara Jul 12, 2025
b48dbb3
chore: add explanation comment
0xAlunara Jul 12, 2025
6d5278b
Merge pull request #1155 from curvefi/refactor/remove-combine-queries
0xAlunara Jul 14, 2025
af54cb1
refactor: remove manual cache busting for token usd rates
0xAlunara Jul 14, 2025
8c9c6c9
Merge branch 'main' into refactor/token-query
0xAlunara Jul 14, 2025
2553c45
refactor: remove unnecessary collateral price fetching
0xAlunara Jul 14, 2025
01d8e92
refactor: remove unnecessary deduplication tanstack already does
0xAlunara Jul 16, 2025
8818e84
refactor: get rid of useAllTokenUsdRates and useless fetches
0xAlunara Jul 16, 2025
b2a09f3
Merge branch 'main' into refactor/token-query
0xAlunara Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions apps/main/src/app/crvusd/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export function CrvUsdClientLayout({ children, serverData }: { children: ReactNo
const chainId = networksIdMapper[networkId]
const { llamaApi: curve = null } = useConnection()
const isPageVisible = useLayoutStore((state) => state.isPageVisible)
const fetchAllStoredUsdRates = useStore((state) => state.usdRates.fetchAllStoredUsdRates)
const fetchGasInfo = useStore((state) => state.gas.fetchGasInfo)
const hydrate = useStore((s) => s.hydrate)

Expand All @@ -39,7 +38,6 @@ export function CrvUsdClientLayout({ children, serverData }: { children: ReactNo
usePageVisibleInterval(
() => {
if (isPageVisible && curve) {
void fetchAllStoredUsdRates(curve)
void fetchGasInfo(curve)
}
},
Expand Down
5 changes: 1 addition & 4 deletions apps/main/src/app/dao/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,18 @@ import { type ReactNode } from 'react'
import networks, { networksIdMapper } from '@/dao/networks'
import useStore from '@/dao/store/useStore'
import { type UrlParams } from '@/dao/types/dao.types'
import { useConnection } from '@ui-kit/features/connect-wallet'
import { useLayoutStore } from '@ui-kit/features/layout'
import { useHydration } from '@ui-kit/hooks/useHydration'
import usePageVisibleInterval from '@ui-kit/hooks/usePageVisibleInterval'
import { useRedirectToEth } from '@ui-kit/hooks/useRedirectToEth'
import { REFRESH_INTERVAL } from '@ui-kit/lib/model'

const useAutoRefresh = (isHydrated: boolean) => {
const { curveApi } = useConnection()
const fetchAllStoredUsdRates = useStore((state) => state.usdRates.fetchAllStoredUsdRates)
const isPageVisible = useLayoutStore((state) => state.isPageVisible)
const getGauges = useStore((state) => state.gauges.getGauges)
const getGaugesData = useStore((state) => state.gauges.getGaugesData)
usePageVisibleInterval(
() => Promise.all([curveApi && fetchAllStoredUsdRates(curveApi), getGauges(), getGaugesData()]),
() => Promise.all([getGauges(), getGaugesData()]),
REFRESH_INTERVAL['5m'],
isPageVisible && isHydrated,
)
Expand Down
2 changes: 0 additions & 2 deletions apps/main/src/app/dex/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const useAutoRefresh = (networkDef: NetworkDef) => {
const fetchPoolsTvl = useStore((state) => state.pools.fetchPoolsTvl)
const setTokensMapper = useStore((state) => state.tokens.setTokensMapper)
const fetchGasInfo = useStore((state) => state.gas.fetchGasInfo)
const fetchAllStoredUsdRates = useStore((state) => state.usdRates.fetchAllStoredUsdRates)
const fetchAllStoredBalances = useStore((state) => state.userBalances.fetchAllStoredBalances)
const network = useStore((state) => state.networks.networks[networkDef.chainId])

Expand All @@ -50,7 +49,6 @@ const useAutoRefresh = (networkDef: NetworkDef) => {
() => {
if (curveApi) {
void fetchGasInfo(curveApi)
void fetchAllStoredUsdRates(curveApi)
void fetchPoolsVolumeTvl(curveApi)

if (curveApi.signerAddress) {
Expand Down
3 changes: 2 additions & 1 deletion apps/main/src/dao/components/DetailInfoEstGas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import DetailInfo from '@ui/DetailInfo'
import IconTooltip from '@ui/Tooltip/TooltipIcon'
import { FORMAT_OPTIONS, formatNumber } from '@ui/utils'
import { t } from '@ui-kit/lib/i18n'
import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { gweiToEther, weiToGwei } from '@ui-kit/utils'

export type StepProgress = {
Expand All @@ -34,7 +35,7 @@ const DetailInfoEstGas = ({
stepProgress?: StepProgress | null
}) => {
const { gasPricesDefault } = networks[chainId]
const chainTokenUsdRate = useStore((state) => state.usdRates.usdRatesMapper[ethAddress])
const { data: chainTokenUsdRate } = useTokenUsdRate({ chainId, tokenAddress: ethAddress })
const gasInfo = useStore((state) => state.gas.gasInfo)
const basePlusPriority = useStore((state) => state.gas.gasInfo?.basePlusPriority?.[gasPricesDefault])

Expand Down
8 changes: 4 additions & 4 deletions apps/main/src/dao/components/PageAnalytics/CrvStats/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import styled from 'styled-components'
import MetricsComp, { MetricsColumnData } from '@/dao/components/MetricsComp'
import { CONTRACT_CRV } from '@/dao/constants'
import { useStatsVecrvQuery } from '@/dao/entities/stats-vecrv'
import useStore from '@/dao/store/useStore'
import Box from '@ui/Box'
import Tooltip from '@ui/Tooltip'
import { formatNumber } from '@ui/utils'
import { useConnection, useWallet } from '@ui-kit/features/connect-wallet'
import { t } from '@ui-kit/lib/i18n'
import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { Chain } from '@ui-kit/utils/network'

const CrvStats = () => {
Expand All @@ -15,15 +17,13 @@ const CrvStats = () => {
const { curveApi: { chainId } = {} } = useConnection()
const veCrvFees = useStore((state) => state.analytics.veCrvFees)
const veCrvHolders = useStore((state) => state.analytics.veCrvHolders)
const usdRatesLoading = useStore((state) => state.usdRates.loading)
const usdRatesMapper = useStore((state) => state.usdRates.usdRatesMapper)
const crv = usdRatesMapper.crv
const { data: crv, isFetching: isLoadingCrv } = useTokenUsdRate({ chainId, tokenAddress: CONTRACT_CRV })

// protect against trying to load data on non-mainnet networks
const notMainnet = chainId !== Chain.Ethereum
const noProvider = !provider || notMainnet
const veCrvFeesLoading = veCrvFees.fetchStatus === 'LOADING'
const aprLoading = statsLoading || veCrvFeesLoading || usdRatesLoading || !crv
const aprLoading = statsLoading || veCrvFeesLoading || isLoadingCrv || crv == null

const veCrvApr =
aprLoading || notMainnet || !statsSuccess
Expand Down
14 changes: 7 additions & 7 deletions apps/main/src/dao/hooks/useEstimateGasConversion.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { useMemo } from 'react'
import { ethAddress } from 'viem'
import { useChainId } from 'wagmi'
import networks from '@/dao/networks'
import useStore from '@/dao/store/useStore'
import { BN, formatNumber } from '@ui/utils'
import { requireLib } from '@ui-kit/features/connect-wallet'
import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { gweiToEther, weiToGwei } from '@ui-kit/utils'

const useEstimateGasConversion = (gas: number | null | undefined) => {
const curve = requireLib('curveApi')
const chainId = curve?.chainId
const chainTokenUsdRate = useStore().usdRates.usdRatesMapper['0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee']
const chainId = useChainId()
const { data: chainTokenUsdRate } = useTokenUsdRate({ chainId, tokenAddress: ethAddress })

const gasPricesDefault = chainId && networks[chainId].gasPricesDefault
const basePlusPriorities = useStore().gas.gasInfo?.basePlusPriority

return useMemo(() => {
const basePlusPriority =
basePlusPriorities && typeof gasPricesDefault !== 'undefined' && basePlusPriorities[gasPricesDefault]

if (!curve || !chainId) return { estGasCost: undefined, estGasCostUsd: undefined, tooltip: undefined }

if (!basePlusPriority || !gas) return { estGasCost: undefined, estGasCostUsd: undefined, tooltip: undefined }

const { symbol, gasPricesUnit } = networks[chainId]
Expand All @@ -30,7 +30,7 @@ const useEstimateGasConversion = (gas: number | null | undefined) => {
const tooltip = `${formatNumber(estGasCost.toString())} ${symbol} at ${gasAmountUnit} ${gasPricesUnit}`
return { estGasCost: estGasCost.toString(), estGasCostUsd, tooltip }
}
}, [gas, curve, chainId, chainTokenUsdRate, gasPricesDefault, basePlusPriorities])
}, [gas, chainId, chainTokenUsdRate, gasPricesDefault, basePlusPriorities])
}

export default useEstimateGasConversion
18 changes: 1 addition & 17 deletions apps/main/src/dao/lib/curvejs.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
import type { FormType as LockFormType } from '@/dao/components/PageVeCrv/types'
import { CurveApi, Provider, EstimatedGas, UsdRatesMapper, ClaimButtonsKey } from '@/dao/types/dao.types'
import { CurveApi, Provider, EstimatedGas, ClaimButtonsKey } from '@/dao/types/dao.types'
import { getErrorMessage } from '@/dao/utils'
import type { DateValue } from '@internationalized/date'
import PromisePool from '@supercharge/promise-pool/dist'
import { log } from '@ui-kit/lib'
import dayjs from '@ui-kit/lib/dayjs'
import { waitForTransaction, waitForTransactions } from '@ui-kit/lib/ethers'

export const helpers = {
waitForTransaction,
waitForTransactions,
fetchUsdRates: async (curve: CurveApi, tokenAddresses: string[]) => {
log('fetchUsdRates', tokenAddresses.length)
const results: UsdRatesMapper = {}

await PromisePool.for(tokenAddresses)
.withConcurrency(5)
.handleError((error, tokenAddress) => {
console.error(`Unable to get usd rate for ${tokenAddress}`, error)
results[tokenAddress] = NaN
})
.process(async (tokenAddress) => {
results[tokenAddress] = await curve.getUsdRate(tokenAddress)
})
return results
},
}

const lockCrv = {
Expand Down
3 changes: 1 addition & 2 deletions apps/main/src/dao/store/createAppSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,11 @@ const createAppSlice = (set: SetState<State>, get: GetState<State>): AppSlice =>
isNetworkSwitched,
})

const { usdRates, user, gas, gauges } = get()
const { user, gas, gauges } = get()
if (isNetworkSwitched) gas.resetState()
await Promise.all([
api && isNetworkSwitched && gas.fetchGasInfo(api),
api && wallet?.provider && user.updateUserData(api, wallet),
api && usdRates.fetchAllStoredUsdRates(api),
gauges.getGauges(),
gauges.getGaugesData(),
])
Expand Down
92 changes: 0 additions & 92 deletions apps/main/src/dao/store/createUsdRatesSlice.ts

This file was deleted.

11 changes: 1 addition & 10 deletions apps/main/src/dao/store/useStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,8 @@ import createGaugesSlice, { GaugesSlice } from '@/dao/store/createGaugesSlice'
import createProposalsSlice, { ProposalsSlice } from '@/dao/store/createProposalsSlice'
import createUserSlice, { UserSlice } from '@/dao/store/createUserSlice'
import createLockedCrvSlice, { LockedCrvSlice } from './createLockedCrvSlice'
import createUsdRatesSlice, { UsdRatesSlice } from './createUsdRatesSlice'

export type State = AppSlice &
GasSlice &
ProposalsSlice &
UserSlice &
GaugesSlice &
AnalyticsSlice &
LockedCrvSlice &
UsdRatesSlice
export type State = AppSlice & GasSlice & ProposalsSlice & UserSlice & GaugesSlice & AnalyticsSlice & LockedCrvSlice

const store = (set: SetState<State>, get: GetState<State>): State => ({
...createAppSlice(set, get),
Expand All @@ -27,7 +19,6 @@ const store = (set: SetState<State>, get: GetState<State>): State => ({
...createUserSlice(set, get),
...createAnalyticsSlice(set, get),
...createLockedCrvSlice(set, get),
...createUsdRatesSlice(set, get),
})

const useStore = process.env.NODE_ENV === 'development' ? create(devtools(store)) : create(store)
Expand Down
1 change: 0 additions & 1 deletion apps/main/src/dao/types/dao.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export type GasInfo = {
l1GasPriceWei?: number
l2GasPriceWei?: number
}
export type UsdRatesMapper = { [tokenAddress: string]: number | undefined }
export type CurveJsProposalType = 'PARAMETER' | 'OWNERSHIP'

export type PricesGaugeOverviewData = {
Expand Down
15 changes: 7 additions & 8 deletions apps/main/src/dex/components/ChipToken.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useMemo, useRef } from 'react'
import { useMemo, useRef, useState } from 'react'
import type { AriaButtonProps } from 'react-aria'
import { useButton } from 'react-aria'
import styled from 'styled-components'
import useStore from '@/dex/store/useStore'
import { useChainId } from 'wagmi'
import Icon from '@ui/Icon'
import Spinner from '@ui/Spinner'
import { formatNumberUsdRate } from '@ui/utils'
import { useConnection } from '@ui-kit/features/connect-wallet'
import { fetchTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { copyToClipboard } from '@ui-kit/utils'

interface ButtonProps extends AriaButtonProps {
Expand Down Expand Up @@ -46,14 +46,13 @@ interface ChipTokenProps extends AriaButtonProps {
}

const ChipToken = ({ className, isHighlight, tokenName, tokenAddress, ...props }: ChipTokenProps) => {
const { curveApi } = useConnection()
const usdRate = useStore((state) => state.usdRates.usdRatesMapper[tokenAddress])
const fetchUsdRateByToken = useStore((state) => state.usdRates.fetchUsdRateByToken)
const chainId = useChainId()
const [usdRate, setUsdRate] = useState<number | undefined>(undefined)
const parsedUsdRate = formatNumberUsdRate(usdRate)

const handleMouseEnter = (foundUsdRate?: string) => {
if (!foundUsdRate && curveApi) {
void fetchUsdRateByToken(curveApi, tokenAddress)
if (!foundUsdRate) {
void fetchTokenUsdRate({ chainId, tokenAddress }).then(setUsdRate)
}
}

Expand Down
3 changes: 2 additions & 1 deletion apps/main/src/dex/components/DetailInfoEstGas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import IconTooltip from '@ui/Tooltip/TooltipIcon'
import { FORMAT_OPTIONS, formatNumber } from '@ui/utils'
import { useConnection } from '@ui-kit/features/connect-wallet'
import { t } from '@ui-kit/lib/i18n'
import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { Chain, gweiToEther, weiToGwei } from '@ui-kit/utils'

export type StepProgress = {
Expand All @@ -34,7 +35,7 @@ const DetailInfoEstGas = ({
const { curveApi } = useConnection()
const networks = useStore((state) => state.networks.networks)
const { gasPricesDefault } = networks[chainId]
const chainTokenUsdRate = useStore((state) => state.usdRates.usdRatesMapper[ethAddress])
const { data: chainTokenUsdRate } = useTokenUsdRate({ chainId, tokenAddress: ethAddress })
const gasInfo = useStore((state) => state.gas.gasInfo)
const basePlusPriority = useStore((state) => state.gas.gasInfo?.basePlusPriority?.[gasPricesDefault])

Expand Down
Loading
Loading