Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 22 additions & 12 deletions apps/main/src/llamalend/LlamaMarketsPage/cells/PriceCell.tsx
Original file line number Diff line number Diff line change
@@ -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<LlamaMarket, number>) => {
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 =
{
Expand All @@ -24,22 +31,25 @@ export const PriceCell = ({ getValue, row, column }: CellContext<LlamaMarket, nu
if (!value) {
return statsError && <ErrorCell error={statsError} />
}
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 (
<Stack direction="column" spacing={1} alignItems="end">
<Tooltip title={`${formatNumber(value, { showAllFractionDigits: true })} ${symbol}`}>
<Stack direction="row" spacing={1} alignItems="center" whiteSpace="nowrap">
<Typography variant="tableCellMBold">{formatNumber(value, { notation: 'compact' })}</Typography>
<TokenIcon blockchainId={chain} address={address} size="mui-md" />
</Stack>
<WithSkeleton loading={isLoading}>
<Stack direction="row" spacing={1} alignItems="center" whiteSpace="nowrap">
<Typography variant="tableCellMBold">{formatNumber(value, { notation: 'compact' })}</Typography>
<TokenIcon blockchainId={chain} address={address} size="mui-md" />
</Stack>
</WithSkeleton>
</Tooltip>
<Tooltip title={usdTooltip}>
<Typography variant="bodySRegular" color="text.secondary">
{usdValue}
</Typography>
<Tooltip title={formatNumber(usdValue, { currency: 'USD', showAllFractionDigits: true })}>
<WithSkeleton loading={isLoading || isUsdRateLoading}>
<Typography variant="bodySRegular" color="text.secondary">
{formatNumber(usdValue, { currency: 'USD', notation: 'compact' })}
</Typography>
</WithSkeleton>
</Tooltip>
</Stack>
)
Expand Down
19 changes: 16 additions & 3 deletions apps/main/src/llamalend/entities/llama-market-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -47,5 +59,6 @@ export function useUserMarketStats(market: LlamaMarket, column?: LlamaMarketColu
}),
...(enableEarnings && { data: { earnings: earnData } }),
...(error && { error }),
isLoading,
}
}
15 changes: 5 additions & 10 deletions apps/main/src/llamalend/entities/llama-markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -113,15 +112,13 @@ const convertLendingVault = (
assets: {
borrowed: {
...borrowedToken,
usdPrice: totalDebt && totalDebtUsd / totalDebt,
chain,
balance: totalDebt,
balanceUsd: totalDebtUsd,
},
collateral: {
...collateralToken,
chain,
usdPrice: totalAssets && totalAssetsUsd / totalAssets,
balance: totalAssets,
balanceUsd: totalAssetsUsd,
},
Expand Down Expand Up @@ -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 = (
Expand All @@ -189,9 +186,9 @@ const convertMintMarket = (
llamma,
rate,
borrowed,
borrowedUsd,
borrowable,
debtCeiling,
stablecoin_price,
chain,
}: MintMarket,
favoriteMarkets: Set<Address>,
Expand All @@ -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,
Expand All @@ -230,7 +225,7 @@ const convertMintMarket = (
debtCeiling,
liquidityUsd: borrowable,
tvl: collateralAmountUsd,
totalDebtUsd: borrowed * stablecoin_price,
totalDebtUsd: borrowedUsd,
totalCollateralUsd: collateralAmountUsd,
rates: {
borrowApy: rate * 100,
Expand Down
43 changes: 10 additions & 33 deletions apps/main/src/llamalend/entities/mint-markets.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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<MintMarket[]> =>
(
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,
})

Expand All @@ -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<Chain, Address[]>,
queryFn: async ({ userAddress }: UserQuery): Promise<Record<Chain, Address[]>> =>
mapRecord(await getAllUserMarkets(userAddress), (_, userMarkets) => userMarkets.map((market) => market.controller)),
validationSuite: userAddressValidationSuite,
})

Expand Down
14 changes: 1 addition & 13 deletions apps/main/src/llamalend/entities/usd-prices.ts
Original file line number Diff line number Diff line change
@@ -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({
Comment thread
DanielSchiavini marked this conversation as resolved.
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}`)
Expand All @@ -12,13 +10,3 @@ const { fetchQuery: fetchCoinPrice } = queryFactory({
},
validationSuite: contractValidationSuite,
})

export const getCoinPrices = async (stablecoinAddresses: Address[], chain: Chain): Promise<Record<string, number>> =>
Object.fromEntries(
await Promise.all(
stablecoinAddresses.map(async (contractAddress) => [
contractAddress,
await fetchCoinPrice({ blockchainId: chain, contractAddress }),
]),
),
)
3 changes: 2 additions & 1 deletion packages/prices-api/src/crvusd/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type Market = {
llamma: Address
rate: number
borrowed: number
borrowedUsd: number
borrowable: number
collateralAmount: number
collateralAmountUsd: number
Expand Down Expand Up @@ -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
}[]
Expand Down
1 change: 1 addition & 0 deletions packages/prices-api/src/crvusd/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion packages/prices-api/src/crvusd/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -101,7 +102,7 @@ export type GetUserMarketsResponse = {
count: number
markets: {
collateral: string
controller: string
controller: Address
first_snapshot: string
last_snapshot: string
}[]
Expand Down