Skip to content

feat: add rebasing yield support to lending and borrowing rates #1144

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,39 @@ const messages = {
const rateType = 'borrow' as const

const BorrowRateTooltipContent = ({ market }: { market: LlamaMarket }) => {
const { rewards, type: marketType, rates } = market
const {
rewards,
type: marketType,
rates,
rates: { borrow: borrowRate, borrowTotalApy },
assets: {
collateral: { rebasingYield, symbol: collateralSymbol },
},
} = market
const { rate, averageRate, period } = useSnapshots(market, rateType)
const poolRewards = useFilteredRewards(rewards, marketType, rateType)
const extraIncentives = useMarketExtraIncentives(rateType, rates)

return (
<Stack gap={Spacing.sm}>
<Typography color="textSecondary">{messages[marketType]}</Typography>
<Stack>
{(poolRewards.length > 0 || extraIncentives.length > 0) && (
{(poolRewards.length > 0 || extraIncentives.length > 0 || !!rebasingYield) && (
<TooltipItems secondary>
<TooltipItem loading={rate == null} title={t`Borrow Rate`}>
{formatPercent(rate)}
<TooltipItem title={t`Borrow Rate`}>
{formatPercent(borrowRate)}
</TooltipItem>
<RewardsTooltipItems title={t`Borrowing incentives`} {...{ poolRewards, extraIncentives }} />
{!!rebasingYield && (
<TooltipItem subitem title={collateralSymbol}>
{formatPercent(rebasingYield)}
</TooltipItem>
)}
</TooltipItems>
)}
<TooltipItems>
<TooltipItem primary loading={rate == null} title={t`Total Borrow Rate`}>
{formatPercent(rate)}
<TooltipItem primary title={t`Total Borrow Rate`}>
{formatPercent(borrowTotalApy)}
</TooltipItem>
<TooltipItem subitem loading={averageRate == null} title={`${period} ${t`Average`}`}>
{formatPercent(averageRate)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,42 @@ const { Spacing } = SizesAndSpaces
const rateType = 'lend' as const

const LendRateTooltipContent = ({ market }: { market: LlamaMarket }) => {
const { rate, averageRate, period, maxBoostedAprAverage } = useSnapshots(market, rateType)
const { averageRate, period, maxBoostedAprAverage } = useSnapshots(market, rateType)
const {
rates,
rates: { lendCrvAprBoosted, lendCrvAprUnboosted },
assets: { collateral },
rates: { lend, lendApr, lendCrvAprBoosted },
assets: { borrowed },
rewards,
type: marketType,
} = market
const poolRewards = useFilteredRewards(rewards, marketType, rateType)
const extraIncentives = useMarketExtraIncentives(rateType, rates)
const yieldBearing = collateral.symbol === 'wstETH' // todo: show yield bearing assets APR with API data
return (
<Stack gap={Spacing.sm}>
<Stack>
<Typography color="textSecondary">
{t`The supply yield is the estimated earnings related to your share of the pool. `}
{t`It varies according to the market and the monetary policy.`}
</Typography>
{yieldBearing && (
{!!borrowed.rebasingYield && (
<Typography color="textSecondary">{t`The collateral of this market is yield bearing and offer extra yield.`}</Typography>
)}
</Stack>
<Stack>
<TooltipItems secondary>
<TooltipItem loading={rate == null} title={t`Lending fees`}>
{formatPercent(rate)}
<TooltipItem title={t`Lending fees`}>
{formatPercent(lendApr)}
</TooltipItem>
{!!borrowed.rebasingYield && (
<TooltipItem subitem title={borrowed.symbol}>
{formatPercent(borrowed.rebasingYield)}
</TooltipItem>
)}
<RewardsTooltipItems title={t`Staking incentives`} {...{ poolRewards, extraIncentives }} />
</TooltipItems>
<TooltipItems>
<TooltipItem primary loading={rate == null} title={`${t`Total base APR`}`}>
{formatPercent((rate ?? 0) + (lendCrvAprUnboosted ?? 0))}
<TooltipItem primary title={`${t`Total base APR`}`}>
{formatPercent(lend)}
</TooltipItem>
<TooltipItem subitem loading={averageRate == null} title={`${period} ${t`Average`}`}>
{formatPercent(averageRate)}
Expand All @@ -62,8 +66,8 @@ const LendRateTooltipContent = ({ market }: { market: LlamaMarket }) => {
)}
{lendCrvAprBoosted ? (
<TooltipItems>
<TooltipItem primary loading={rate == null} title={`${t`Total max veCRV APR`}`}>
{formatPercent((rate ?? 0) + lendCrvAprBoosted)}
<TooltipItem primary title={`${t`Total max veCRV APR`}`}>
{formatPercent((lendApr ?? 0) + lendCrvAprBoosted)}
</TooltipItem>
<TooltipItem subitem loading={maxBoostedAprAverage == null} title={t`7D average`}>
{formatPercent(maxBoostedAprAverage)}
Expand Down
31 changes: 25 additions & 6 deletions apps/main/src/llamalend/entities/llama-markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type AssetDetails = {
usdPrice: number | null
balance: number | null
balanceUsd: number | null
rebasingYield: number | null
}

export type LlamaMarket = {
Expand All @@ -41,11 +42,12 @@ export type LlamaMarket = {
liquidityUsd: number
debtCeiling: number | null // only for mint markets, null for lend markets
rates: {
lend: number | null // lendApr + incentives (for now only lendCrvAprUnboosted)
lendApr: number | null
lend: number | null // lendApr + CRV unboosted + yield from collateral
lendApr: number | null // base lend APR %
lendCrvAprUnboosted: number | null
lendCrvAprBoosted: number | null
borrow: number // apy %
borrow: number // base borrow APY %
borrowTotalApy: number // borrow - yield from collateral
}
type: LlamaMarketType
url: string
Expand Down Expand Up @@ -88,7 +90,7 @@ const convertLendingVault = (
const hasBorrow = userBorrows.has(controller)
const hasLend = userSupplied.has(vault)
const hasPosition = hasBorrow || hasLend
const lend = lendApr + (lendCrvAprUnboosted ?? 0)
const lend = lendApr + (lendCrvAprUnboosted ?? 0) + (borrowedToken?.rebasingYield ?? 0)
return {
chain,
address: vault,
Expand All @@ -112,7 +114,15 @@ const convertLendingVault = (
utilizationPercent: totalAssetsUsd && (100 * totalDebtUsd) / totalAssetsUsd,
debtCeiling: null, // debt ceiling is not applicable for lend markets
liquidityUsd: totalAssetsUsd - totalDebtUsd,
rates: { lend, lendApr, lendCrvAprUnboosted, lendCrvAprBoosted, borrow: apyBorrow },
rates: {
lend, // this is the total yield, including CRV and collateral yield, and is displayed in the table
lendApr,
lendCrvAprUnboosted,
lendCrvAprBoosted,
borrow: apyBorrow,
// as confusing as it may be, `borrow` is used in the table, but the total borrow is only in the tooltip
borrowTotalApy: apyBorrow - (collateralToken?.rebasingYield ?? 0),
},
type: LlamaMarketType.Lend,
url: getInternalUrl(
'lend',
Expand Down Expand Up @@ -163,6 +173,7 @@ const convertMintMarket = (
chain,
balance: borrowed,
balanceUsd: borrowed * stablecoin_price,
rebasingYield: null,
},
collateral: {
symbol: collateralSymbol,
Expand All @@ -171,12 +182,20 @@ const convertMintMarket = (
chain,
balance: collateralAmount,
balanceUsd: collateralAmountUsd,
rebasingYield: null,
},
},
utilizationPercent: Math.min(100, (100 * borrowed) / debtCeiling), // debt ceiling may be lowered, so cap at 100%
debtCeiling,
liquidityUsd: borrowable,
rates: { borrow: rate * 100, lend: null, lendApr: null, lendCrvAprBoosted: null, lendCrvAprUnboosted: null },
rates: {
borrow: rate * 100,
lend: null,
lendApr: null,
lendCrvAprBoosted: null,
lendCrvAprUnboosted: null,
borrowTotalApy: rate * 100,
},
type: LlamaMarketType.Mint,
deprecatedMessage: DEPRECATED_LLAMAS[llamma]?.(),
url: getInternalUrl(
Expand Down
2 changes: 2 additions & 0 deletions packages/prices-api/src/llamalend/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ export type Market = {
collateralToken: {
symbol: string
address: Address
rebasingYield: number | null
}
borrowedToken: {
symbol: string
address: Address
rebasingYield: number | null
}
leverage: number
}
Expand Down
2 changes: 2 additions & 0 deletions packages/prices-api/src/llamalend/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ export const parseMarket = (x: Responses.GetMarketsResponse['data'][number]): Mo
collateralToken: {
symbol: x.collateral_token.symbol,
address: x.collateral_token.address,
rebasingYield: x.collateral_token.rebasing_yield,
},
borrowedToken: {
symbol: x.borrowed_token.symbol,
address: x.borrowed_token.address,
rebasingYield: x.borrowed_token.rebasing_yield,
},
leverage: x.leverage,
})
Expand Down
2 changes: 2 additions & 0 deletions packages/prices-api/src/llamalend/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ export type GetMarketsResponse = {
collateral_token: {
symbol: string
address: Address
rebasing_yield: number | null
}
borrowed_token: {
symbol: string
address: Address
rebasing_yield: number | null
}
leverage: number
}[]
Expand Down
6 changes: 3 additions & 3 deletions tests/cypress/support/helpers/lending-mocks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MAX_USD_VALUE, oneAddress, oneFloat, oneInt, oneOf, onePrice, range } from '@/support/generators'
import { oneToken } from '@/support/helpers/tokens'
import type { GetMarketsResponse } from '@curvefi/prices-api/dist/llamalend'
import type { GetMarketsResponse } from '@curvefi/prices-api/src/llamalend'
import { fromEntries } from '../../../../packages/prices-api/src/objects.util'

const LendingChains = ['ethereum', 'fraxtal', 'arbitrum'] as const
Expand Down Expand Up @@ -54,8 +54,8 @@ const oneLendingPool = (chain: Chain, utilization: number): GetMarketsResponse['
borrowed_balance: borrowedBalance,
collateral_balance_usd: collateralBalance * collateralPrice,
borrowed_balance_usd: borrowedBalance * borrowedPrice,
collateral_token: { symbol: collateral.symbol, address: collateral.address },
borrowed_token: { symbol: borrowed.symbol, address: borrowed.address },
collateral_token: { symbol: collateral.symbol, address: collateral.address, rebasing_yield: null },
borrowed_token: { symbol: borrowed.symbol, address: borrowed.address, rebasing_yield: null },
}
}

Expand Down
Loading