Skip to content

feat: added new tooltips to borrow/lend/market details #1236

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

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
eeaf59a
feat: added new tooltips to borrow/lend/market details
OnlyJousting Aug 7, 2025
40f08d4
Merge branch 'main' into feat/new-position-detail-tooltips
OnlyJousting Aug 7, 2025
fb7029a
refactor: use ui-kit tooltip helpers in llamalend markets components
OnlyJousting Aug 7, 2025
e3bb12f
feat: add missing fields to getSnapshots model and parser
OnlyJousting Aug 8, 2025
f901da0
chore: bump prices-api to 1.1.13
OnlyJousting Aug 8, 2025
2af4ea5
fix: snapshots endpoint typo
OnlyJousting Aug 9, 2025
7f478cf
feat: market details borrow rate tooltip
OnlyJousting Aug 9, 2025
d8aed74
feat: add market details supply tooltip
OnlyJousting Aug 10, 2025
57091d8
chore: update llamalend model for new fields
OnlyJousting Aug 10, 2025
87f1e3e
feat: add borrow rate tooltip to mint, add rebasing yield, campaign r…
OnlyJousting Aug 10, 2025
ae7aee6
fix: type errors
OnlyJousting Aug 10, 2025
face238
refactor: use ui-kit tooltip components in markets list
OnlyJousting Aug 11, 2025
e8db408
Merge branch 'main' into feat/new-position-detail-tooltips
OnlyJousting Aug 11, 2025
b667874
feat: add rebasingYield to crvusd borrow rate breakdowns
OnlyJousting Aug 11, 2025
239d0ba
Merge branch 'feat/new-position-detail-tooltips' of https://github.co…
OnlyJousting Aug 11, 2025
6dd844b
refactor: use total apy for borrow and supply values
OnlyJousting Aug 11, 2025
704a3b5
fix: review comments
OnlyJousting Aug 12, 2025
53393ad
refactor: more accurately name TooltipContent components
OnlyJousting Aug 12, 2025
bd590c3
Merge branch 'main' of github.com:curvefi/curve-frontend into feat/ne…
DanielSchiavini Aug 13, 2025
e680f37
chore: review
DanielSchiavini Aug 13, 2025
270b6dd
fix: lending snapshot mock missing fields
DanielSchiavini Aug 14, 2025
2dc0b0e
refactor: unify RateType
DanielSchiavini Aug 14, 2025
bb12cff
refactor: avoid useQuery
DanielSchiavini Aug 14, 2025
4d8ae73
refactor: proper enums
DanielSchiavini Aug 14, 2025
3e7aaee
fix: no supply action for mint markets
DanielSchiavini Aug 14, 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
6 changes: 3 additions & 3 deletions apps/main/src/lend/components/MarketInformationTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { Box } from '@mui/material'
import { t } from '@ui-kit/lib/i18n'
import { TabsSwitcher } from '@ui-kit/shared/ui/TabsSwitcher'

type TabValue = 'borrow' | 'lend'
type TabValue = 'borrow' | 'supply'

type MarketInformationTabsProps = {
currentTab: TabValue
hrefs: {
borrow: string
lend: string
supply: string
}
children: ReactNode
}
Expand All @@ -21,7 +21,7 @@ type MarketInformationTabsProps = {
export const MarketInformationTabs = ({ currentTab, hrefs, children }: MarketInformationTabsProps) => {
const TABS: { value: TabValue; label: string; href: string }[] = [
{ value: 'borrow', label: t`Borrow`, href: hrefs.borrow },
{ value: 'lend', label: t`Lend`, href: hrefs.lend },
{ value: 'supply', label: t`Supply`, href: hrefs.supply },
]
const [tab, setTab] = useState<TabValue>(currentTab)

Expand Down
2 changes: 1 addition & 1 deletion apps/main/src/lend/components/PageLoanCreate/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const Page = (params: MarketUrlParams) => {
}
const positionDetailsHrefs = {
borrow: '',
lend: getVaultPathname(params, rOwmId, 'deposit'),
supply: getVaultPathname(params, rOwmId, 'deposit'),
}

if (!provider) {
Expand Down
2 changes: 1 addition & 1 deletion apps/main/src/lend/components/PageLoanManage/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const Page = (params: MarketUrlParams) => {

const positionDetailsHrefs = {
borrow: '',
lend: getVaultPathname(params, rOwmId, 'deposit'),
supply: getVaultPathname(params, rOwmId, 'deposit'),
}

if (!provider) {
Expand Down
16 changes: 8 additions & 8 deletions apps/main/src/lend/components/PageVault/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { _getSelectedTab } from '@/lend/components/PageLoanManage/utils'
import Vault from '@/lend/components/PageVault/index'
import PageTitleBorrowSupplyLinks from '@/lend/components/SharedPageStyles/PageTitleBorrowSupplyLinks'
import { useOneWayMarket } from '@/lend/entities/chain'
import { useLendPositionDetails } from '@/lend/hooks/useLendPositionDetails'
import { useMarketDetails } from '@/lend/hooks/useMarketDetails'
import { useSupplyPositionDetails } from '@/lend/hooks/useSupplyPositionDetails'
import useTitleMapper from '@/lend/hooks/useTitleMapper'
import { helpers } from '@/lend/lib/apiLending'
import networks from '@/lend/networks'
Expand All @@ -39,7 +39,7 @@ import Tabs, { Tab } from '@ui/Tab'
import { ConnectWalletPrompt, isLoading, useConnection, useWallet } from '@ui-kit/features/connect-wallet'
import { useLayoutStore } from '@ui-kit/features/layout'
import { MarketDetails } from '@ui-kit/features/market-details'
import { LendPositionDetails } from '@ui-kit/features/market-position-details'
import { SupplyPositionDetails } from '@ui-kit/features/market-position-details'
import { NoPosition } from '@ui-kit/features/market-position-details/NoPosition'
import { useUserProfileStore } from '@ui-kit/features/user-profile'
import { useBetaFlag } from '@ui-kit/hooks/useLocalStorage'
Expand Down Expand Up @@ -75,9 +75,9 @@ const Page = (params: MarketUrlParams) => {
const [isLoaded, setLoaded] = useState(false)
const [isBeta] = useBetaFlag()

const lendPositionDetails = useLendPositionDetails({
const supplyPositionDetails = useSupplyPositionDetails({
chainId: rChainId,
market: market,
market,
marketId: rOwmId,
})
const marketDetails = useMarketDetails({
Expand Down Expand Up @@ -142,9 +142,9 @@ const Page = (params: MarketUrlParams) => {
const borrowPathnameFn = loanExists ? getLoanManagePathname : getLoanCreatePathname
const positionDetailsHrefs = {
borrow: borrowPathnameFn(params, rOwmId, ''),
lend: '',
supply: '',
}
const hasSupplyPosition = (lendPositionDetails.shares.value ?? 0) > 0
const hasSupplyPosition = (supplyPositionDetails.shares.value ?? 0) > 0

if (!provider) {
return (
Expand Down Expand Up @@ -240,9 +240,9 @@ const Page = (params: MarketUrlParams) => {
borrowAddress={market?.addresses?.controller || ''}
supplyAddress={market?.addresses?.vault || ''}
/>
<MarketInformationTabs currentTab={'lend'} hrefs={positionDetailsHrefs}>
<MarketInformationTabs currentTab="supply" hrefs={positionDetailsHrefs}>
{hasSupplyPosition ? (
<LendPositionDetails {...lendPositionDetails} />
<SupplyPositionDetails {...supplyPositionDetails} />
) : (
<Stack padding={Spacing.md} sx={{ backgroundColor: (t) => t.design.Layer[1].Fill }}>
<NoPosition type="supply" />
Expand Down
22 changes: 11 additions & 11 deletions apps/main/src/lend/entities/market-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { queryFactory } from '@ui-kit/lib/model/query'
import type { ChainQuery } from '@ui-kit/lib/model/query'
import { llamaApiValidationSuite } from '@ui-kit/lib/model/query/curve-api-validation'

const getLendMarket = (marketId: string) => requireLib('llamaApi').getLendMarket(marketId)

type MarketQuery = ChainQuery<ChainId> & { marketId: string }
type MarketParams = FieldsOf<MarketQuery>

Expand All @@ -14,7 +16,7 @@ type MarketCapAndAvailable = {
available: number
}
type MarketMaxLeverage = {
value: string
maxLeverage: string
}
type MarketCollateralAmounts = {
collateralAmount: number
Expand All @@ -26,8 +28,7 @@ type MarketCollateralAmounts = {
* in order to display the most current data when a wallet is connected.
* */
const _getMarketCapAndAvailable = async ({ marketId }: MarketQuery): Promise<MarketCapAndAvailable> => {
const api = requireLib('llamaApi')
const market = api.getLendMarket(marketId)
const market = getLendMarket(marketId)
const capAndAvailable = await market.stats.capAndAvailable(false, USE_API)
return {
cap: +capAndAvailable.cap,
Expand All @@ -48,10 +49,9 @@ export const { useQuery: useMarketCapAndAvailable, invalidate: invalidateMarketC
* in order to display the most current data when a wallet is connected.
* */
const _getMarketMaxLeverage = async ({ marketId }: MarketQuery): Promise<MarketMaxLeverage> => {
const api = requireLib('llamaApi')
const market = api.getLendMarket(marketId)
const market = getLendMarket(marketId)
const maxLeverage = market.leverage.hasLeverage() ? await market.leverage.maxLeverage(market?.minBands) : ''
return { value: maxLeverage }
return { maxLeverage }
}

export const { useQuery: useMarketMaxLeverage } = queryFactory({
Expand All @@ -66,8 +66,7 @@ export const { useQuery: useMarketMaxLeverage } = queryFactory({
* in order to display the most current data when a wallet is connected.
* */
const _getMarketCollateralAmounts = async ({ marketId }: MarketQuery): Promise<MarketCollateralAmounts> => {
const api = requireLib('llamaApi')
const market = api.getLendMarket(marketId)
const market = getLendMarket(marketId)
const ammBalance = await market.stats.ammBalances(false, USE_API)
return {
collateralAmount: +ammBalance.collateral,
Expand All @@ -84,7 +83,9 @@ export const { useQuery: useMarketCollateralAmounts, invalidate: invalidateMarke
})

const _fetchOnChainMarketRate = async ({ marketId }: MarketQuery) => ({
rates: await requireLib('llamaApi').getLendMarket(marketId).stats.rates(false, false),
rates: await getLendMarket(marketId).stats.rates(false, false),
rewardsApr: await getLendMarket(marketId).vault.rewardsApr(false),
crvRates: await getLendMarket(marketId).vault.crvApr(false),
})

/**
Expand All @@ -101,8 +102,7 @@ export const { useQuery: useMarketOnChainRates, invalidate: invalidateMarketOnCh
})

const _fetchMarketPricePerShare = async ({ marketId }: MarketQuery) => {
const api = requireLib('llamaApi')
const market = api.getLendMarket(marketId)
const market = getLendMarket(marketId)
return await market.vault.previewRedeem(1)
}

Expand Down
28 changes: 20 additions & 8 deletions apps/main/src/lend/hooks/useBorrowPositionDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import networks from '@/lend/networks'
import useStore from '@/lend/store/useStore'
import { ChainId, OneWayMarketTemplate } from '@/lend/types/lend.types'
import type { Address, Chain } from '@curvefi/prices-api'
import { useCampaigns } from '@ui-kit/entities/campaigns'
import { useLendingSnapshots } from '@ui-kit/entities/lending-snapshots'
import { BorrowPositionDetailsProps } from '@ui-kit/features/market-position-details/BorrowPositionDetails'
import { calculateRangeToLiquidation } from '@ui-kit/features/market-position-details/utils'
import { calculateLtv, calculateRangeToLiquidation } from '@ui-kit/features/market-position-details/utils'
import { useTokenUsdRate } from '@ui-kit/lib/model/entities/token-usd-rate'
import { LlamaMarketType } from '@ui-kit/types/market'

type UseBorrowPositionDetailsProps = {
chainId: ChainId
Expand All @@ -23,6 +25,7 @@ export const useBorrowPositionDetails = ({
market,
marketId,
}: UseBorrowPositionDetailsProps): BorrowPositionDetailsProps => {
const { controller } = market?.addresses ?? {}
const { address: userAddress } = useAccount()
const { data: userLoanDetails, isLoading: isUserLoanDetailsLoading } = useUserLoanDetails({
chainId,
Expand All @@ -41,6 +44,7 @@ export const useBorrowPositionDetails = ({
const marketRate = useStore((state) => state.markets.ratesMapper[chainId]?.[marketId])
const prices = useStore((state) => state.markets.pricesMapper[chainId]?.[marketId])

const { data: campaigns } = useCampaigns({})
const { data: onChainRatesData, isLoading: isOnchainRatesLoading } = useMarketOnChainRates({
chainId: chainId,
marketId,
Expand All @@ -53,7 +57,6 @@ export const useBorrowPositionDetails = ({
chainId: chainId,
tokenAddress: market?.addresses?.borrowed_token,
})

const { data: lendSnapshots, isLoading: isLendSnapshotsLoading } = useLendingSnapshots({
blockchainId: networks[chainId].id as Chain,
contractAddress: market?.addresses?.controller as Address,
Expand All @@ -72,25 +75,34 @@ export const useBorrowPositionDetails = ({
return meanBy(recentSnapshots, ({ borrowApy }) => borrowApy) * 100
}, [lendSnapshots])

const borrowApy = onChainRatesData?.rates?.borrowApy ?? marketRate?.rates?.borrowApy

const borrowApy = onChainRatesData?.rates?.borrowApy ?? marketRate?.rates?.borrowApy ?? null
const collateralTotalValue = useMemo(() => {
if (!collateralUsdRate || !collateral || !borrowed) return null
return Number(collateral) * Number(collateralUsdRate) + Number(borrowed)
}, [collateral, borrowed, collateralUsdRate])
const campaignRewards = useMemo(() => {
if (!campaigns || !controller) return []
return [...(campaigns[controller.toLowerCase()] ?? [])]
}, [campaigns, controller])

const rebasingYield = lendSnapshots?.[0]?.collateralToken?.rebasingYield // take most recent rebasing yield
return {
marketType: LlamaMarketType.Lend,
liquidationAlert: {
softLiquidation: status?.colorKey === 'soft_liquidation',
hardLiquidation: status?.colorKey === 'hard_liquidation',
},
health: {
value: Number(healthFull),
value: healthFull ? Number(healthFull) : null,
loading: !market || isUserLoanDetailsLoading,
},
borrowAPY: {
value: borrowApy != null ? Number(borrowApy) : null,
thirtyDayAvgRate: thirtyDayAvgRate,
rate: borrowApy == null ? null : Number(borrowApy),
averageRate: thirtyDayAvgRate,
averageRateLabel: '30D',
rebasingYield: rebasingYield ?? null,
totalBorrowRate: borrowApy == null ? null : Number(borrowApy) - (rebasingYield ?? 0),
extraRewards: campaignRewards,
loading: !market || isOnchainRatesLoading || isLendSnapshotsLoading || !market?.addresses.controller,
},
liquidationRange: {
Expand Down Expand Up @@ -120,7 +132,7 @@ export const useBorrowPositionDetails = ({
loading: !market || isUserLoanDetailsLoading || collateralUsdRateLoading || borrowedUsdRateLoading,
},
ltv: {
value: collateralTotalValue && debt ? (Number(debt) / collateralTotalValue) * 100 : null,
value: collateralTotalValue && debt ? calculateLtv(Number(debt), collateralTotalValue) : null,
loading: !market || isUserLoanDetailsLoading,
},
pnl: {
Expand Down
87 changes: 0 additions & 87 deletions apps/main/src/lend/hooks/useLendPositionDetails.ts

This file was deleted.

Loading
Loading