diff --git a/apps/main/src/llamalend/LlamaMarketsPage/cells/PriceCell.tsx b/apps/main/src/llamalend/LlamaMarketsPage/cells/PriceCell.tsx index 72a2ed53c8..83553df5aa 100644 --- a/apps/main/src/llamalend/LlamaMarketsPage/cells/PriceCell.tsx +++ b/apps/main/src/llamalend/LlamaMarketsPage/cells/PriceCell.tsx @@ -1,19 +1,26 @@ import { useUserMarketStats } from '@/llamalend/entities/llama-market-stats' import { LlamaMarket } from '@/llamalend/entities/llama-markets' +import { useTokenUsdPrice } from '@/llamalend/entities/usd-prices' import Stack from '@mui/material/Stack' import Typography from '@mui/material/Typography' import type { CellContext } from '@tanstack/react-table' import { formatNumber } from '@ui/utils' import { TokenIcon } from '@ui-kit/shared/ui/TokenIcon' import { Tooltip } from '@ui-kit/shared/ui/Tooltip' +import { WithSkeleton } from '@ui-kit/shared/ui/WithSkeleton' import { LlamaMarketColumnId } from '../columns.enum' import { ErrorCell } from './ErrorCell' export const PriceCell = ({ getValue, row, column }: CellContext) => { const market = row.original const { assets } = market + const { chain, address, symbol } = assets.borrowed // todo: earnings are usually crv const columnId = column.id as LlamaMarketColumnId - const { data: stats, error: statsError } = useUserMarketStats(market, columnId) + const { data: stats, error: statsError, isLoading } = useUserMarketStats(market, columnId) + const { data: usdPrice, isLoading: isUsdRateLoading } = useTokenUsdPrice({ + blockchainId: chain, + contractAddress: address, + }) const { borrowed, earnings: earningsData } = stats ?? {} const value = { @@ -24,22 +31,25 @@ export const PriceCell = ({ getValue, row, column }: CellContext } - const { usdPrice, chain, address, symbol } = assets.borrowed // todo: earnings are usually crv - const usdValue = usdPrice != null && formatNumber(value * usdPrice, { currency: 'USD', notation: 'compact' }) - const usdTooltip = usdPrice != null && formatNumber(value * usdPrice, { currency: 'USD' }) + const usdValue = usdPrice && formatNumber(value * usdPrice, { currency: 'USD', notation: 'compact' }) + const usdTooltip = usdPrice && formatNumber(value * usdPrice, { currency: 'USD' }) return ( - - {formatNumber(value, { notation: 'compact' })} - - + + + {formatNumber(value, { notation: 'compact' })} + + + - - - {usdValue} - + + + + {formatNumber(usdValue, { currency: 'USD', notation: 'compact' })} + + ) diff --git a/apps/main/src/llamalend/entities/llama-market-stats.ts b/apps/main/src/llamalend/entities/llama-market-stats.ts index c1e2b45d13..1e790dc758 100644 --- a/apps/main/src/llamalend/entities/llama-market-stats.ts +++ b/apps/main/src/llamalend/entities/llama-market-stats.ts @@ -30,12 +30,24 @@ export function useUserMarketStats(market: LlamaMarket, column?: LlamaMarketColu // todo: api will be updated to use controller address for earnings too const earningsParams = { ...params, contractAddress: marketAddress } - const { data: lendData, error: lendError } = useUserLendingVaultStats(params, enableLendingStats) - const { data: earnData, error: earnError } = useUserLendingVaultEarnings(earningsParams, enableEarnings) - const { data: mintData, error: mintError } = useUserMintMarketStats(params, enableMintStats) + const { + data: lendData, + error: lendError, + isLoading: loadingLend, + } = useUserLendingVaultStats(params, enableLendingStats) + + const { + data: earnData, + error: earnError, + isLoading: loadingEarn, + } = useUserLendingVaultEarnings(earningsParams, enableEarnings) + + const { data: mintData, error: mintError, isLoading: loadingMint } = useUserMintMarketStats(params, enableMintStats) const stats = (enableLendingStats && lendData) || (enableMintStats && mintData) const error = (enableLendingStats && lendError) || (enableMintStats && mintError) || (enableEarnings && earnError) + const isLoading = loadingLend || loadingEarn || loadingMint + return { ...(stats && { data: { @@ -47,5 +59,6 @@ export function useUserMarketStats(market: LlamaMarket, column?: LlamaMarketColu }), ...(enableEarnings && { data: { earnings: earnData } }), ...(error && { error }), + isLoading, } } diff --git a/apps/main/src/llamalend/entities/llama-markets.ts b/apps/main/src/llamalend/entities/llama-markets.ts index f3549ccad0..1f8b602c51 100644 --- a/apps/main/src/llamalend/entities/llama-markets.ts +++ b/apps/main/src/llamalend/entities/llama-markets.ts @@ -26,9 +26,8 @@ export type Assets = { export type AssetDetails = { symbol: string - address: string + address: Address chain: Chain - usdPrice: number | null balance: number | null balanceUsd: number | null rebasingYield: number | null @@ -113,7 +112,6 @@ const convertLendingVault = ( assets: { borrowed: { ...borrowedToken, - usdPrice: totalDebt && totalDebtUsd / totalDebt, chain, balance: totalDebt, balanceUsd: totalDebtUsd, @@ -121,7 +119,6 @@ const convertLendingVault = ( collateral: { ...collateralToken, chain, - usdPrice: totalAssets && totalAssetsUsd / totalAssets, balance: totalAssets, balanceUsd: totalAssetsUsd, }, @@ -176,7 +173,7 @@ const convertLendingVault = ( } /** We show WETH as ETH in the UI and market URL. Also change address so the symbol is correct */ -const getCollateral = ({ address, symbol }: { address: Address; symbol: string }) => +const getCollateral = ({ address, symbol }: { address: Address; symbol: string }): [string, Address] => symbol == 'WETH' ? ['ETH', ethAddress] : [symbol, address] const convertMintMarket = ( @@ -189,9 +186,9 @@ const convertMintMarket = ( llamma, rate, borrowed, + borrowedUsd, borrowable, debtCeiling, - stablecoin_price, chain, }: MintMarket, favoriteMarkets: Set
, @@ -210,16 +207,14 @@ const convertMintMarket = ( borrowed: { symbol: stablecoinToken.symbol, address: stablecoinToken.address, - usdPrice: stablecoin_price, chain, balance: borrowed, - balanceUsd: borrowed * stablecoin_price, + balanceUsd: borrowedUsd, rebasingYield: stablecoinToken.rebasingYield ? Number(stablecoinToken.rebasingYield) : null, }, collateral: { symbol: collateralSymbol, address: collateralAddress, - usdPrice: collateralAmountUsd / collateralAmount, chain, balance: collateralAmount, balanceUsd: collateralAmountUsd, @@ -230,7 +225,7 @@ const convertMintMarket = ( debtCeiling, liquidityUsd: borrowable, tvl: collateralAmountUsd, - totalDebtUsd: borrowed * stablecoin_price, + totalDebtUsd: borrowedUsd, totalCollateralUsd: collateralAmountUsd, rates: { borrowApy: rate * 100, diff --git a/apps/main/src/llamalend/entities/mint-markets.ts b/apps/main/src/llamalend/entities/mint-markets.ts index 787f9aaf3f..ad2ce23fb3 100644 --- a/apps/main/src/llamalend/entities/mint-markets.ts +++ b/apps/main/src/llamalend/entities/mint-markets.ts @@ -1,7 +1,11 @@ -import lodash from 'lodash' import { Chain } from '@curvefi/prices-api' -import { getAllMarkets, getAllUserMarkets, getUserMarketStats, Market } from '@curvefi/prices-api/crvusd' -import { recordEntries } from '@curvefi/prices-api/objects.util' +import { + getAllMarkets, + getAllUserMarkets, + getUserMarketStats, + Market as MintMarketFromApi, +} from '@curvefi/prices-api/crvusd' +import { mapRecord, recordEntries } from '@curvefi/prices-api/objects.util' import { queryFactory, type UserParams, type UserQuery } from '@ui-kit/lib/model/query' import { userAddressValidationSuite } from '@ui-kit/lib/model/query/user-address-validation' import { @@ -11,37 +15,15 @@ import { } from '@ui-kit/lib/model/query/user-contract' import { EmptyValidationSuite } from '@ui-kit/lib/validation' import { Address } from '@ui-kit/utils' -import { getCoinPrices } from './usd-prices' - -type MintMarketFromApi = Market export type MintMarket = MintMarketFromApi & { - stablecoin_price: number chain: Chain } -/** - * Note: The API does not provide stablecoin prices, fetch them separately and add them to the data. - * I requested benber86 to add stablecoin prices to the API, but it may take some time. - */ -async function addStableCoinPrices({ chain, data }: { chain: Chain; data: MintMarketFromApi[] }) { - const stablecoinAddresses = lodash.uniq(data.map((market) => market.stablecoinToken.address)) - const stablecoinPrices = await getCoinPrices(stablecoinAddresses, chain) - return data.map((market) => ({ - ...market, - chain, - stablecoin_price: stablecoinPrices[market.stablecoinToken.address], - })) -} - export const { getQueryOptions: getMintMarketOptions, invalidate: invalidateMintMarkets } = queryFactory({ queryKey: () => ['mint-markets', 'v2'] as const, queryFn: async (): Promise => - ( - await Promise.all( - recordEntries(await getAllMarkets()).flatMap(([chain, data]) => addStableCoinPrices({ chain, data })), - ) - ).flat(), + recordEntries(await getAllMarkets()).flatMap(([chain, markets]) => markets.map((market) => ({ ...market, chain }))), validationSuite: EmptyValidationSuite, }) @@ -51,13 +33,8 @@ const { invalidate: invalidateUserMintMarkets, } = queryFactory({ queryKey: ({ userAddress }: UserParams) => ['user-mint-markets', { userAddress }, 'v1'] as const, - queryFn: async ({ userAddress }: UserQuery) => - Object.fromEntries( - Object.entries(await getAllUserMarkets(userAddress)).map(([chain, userMarkets]) => [ - chain, - userMarkets.map((market) => market.controller), - ]), - ) as Record, + queryFn: async ({ userAddress }: UserQuery): Promise> => + mapRecord(await getAllUserMarkets(userAddress), (_, userMarkets) => userMarkets.map((market) => market.controller)), validationSuite: userAddressValidationSuite, }) diff --git a/apps/main/src/llamalend/entities/usd-prices.ts b/apps/main/src/llamalend/entities/usd-prices.ts index 957609fac6..a48c3a33a8 100644 --- a/apps/main/src/llamalend/entities/usd-prices.ts +++ b/apps/main/src/llamalend/entities/usd-prices.ts @@ -1,9 +1,7 @@ -import type { Chain } from '@curvefi/prices-api' import { ContractParams, queryFactory, rootKeys } from '@ui-kit/lib/model' import { contractValidationSuite } from '@ui-kit/lib/model/query/contract-validation' -import type { Address } from '@ui-kit/utils' -const { fetchQuery: fetchCoinPrice } = queryFactory({ +export const { useQuery: useTokenUsdPrice } = queryFactory({ queryKey: (params: ContractParams) => [...rootKeys.contract(params), 'usd-price'] as const, queryFn: async ({ blockchainId, contractAddress }: ContractParams) => { const response = await fetch(`https://prices.curve.finance/v1/usd_price/${blockchainId}/${contractAddress}`) @@ -12,13 +10,3 @@ const { fetchQuery: fetchCoinPrice } = queryFactory({ }, validationSuite: contractValidationSuite, }) - -export const getCoinPrices = async (stablecoinAddresses: Address[], chain: Chain): Promise> => - Object.fromEntries( - await Promise.all( - stablecoinAddresses.map(async (contractAddress) => [ - contractAddress, - await fetchCoinPrice({ blockchainId: chain, contractAddress }), - ]), - ), - ) diff --git a/packages/prices-api/src/crvusd/models.ts b/packages/prices-api/src/crvusd/models.ts index c852c8461c..ea7f43f40f 100644 --- a/packages/prices-api/src/crvusd/models.ts +++ b/packages/prices-api/src/crvusd/models.ts @@ -7,6 +7,7 @@ export type Market = { llamma: Address rate: number borrowed: number + borrowedUsd: number borrowable: number collateralAmount: number collateralAmountUsd: number @@ -96,7 +97,7 @@ export type Keeper = { /** More specifically, the markets where a user holds a position */ export type UserMarkets = { collateral: string - controller: string + controller: Address snapshotFirst: Date snapshotLast: Date }[] diff --git a/packages/prices-api/src/crvusd/parsers.ts b/packages/prices-api/src/crvusd/parsers.ts index 3d34d13d8d..64d6c43148 100644 --- a/packages/prices-api/src/crvusd/parsers.ts +++ b/packages/prices-api/src/crvusd/parsers.ts @@ -10,6 +10,7 @@ export const parseMarket = (x: Responses.GetMarketsResponse['data'][number]): Mo llamma: x.llamma, rate: x.rate, borrowed: x.total_debt, + borrowedUsd: x.total_debt_usd, borrowable: x.borrowable, collateralAmount: x.collateral_amount, collateralAmountUsd: x.collateral_amount_usd, diff --git a/packages/prices-api/src/crvusd/responses.ts b/packages/prices-api/src/crvusd/responses.ts index e418176ab6..f3df4ec0c3 100644 --- a/packages/prices-api/src/crvusd/responses.ts +++ b/packages/prices-api/src/crvusd/responses.ts @@ -7,6 +7,7 @@ export type GetMarketsResponse = { llamma: Address rate: number total_debt: number + total_debt_usd: number n_loans: number debt_ceiling: number borrowable: number @@ -101,7 +102,7 @@ export type GetUserMarketsResponse = { count: number markets: { collateral: string - controller: string + controller: Address first_snapshot: string last_snapshot: string }[]