diff --git a/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/BorrowRateTooltip.tsx b/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/BorrowRateTooltip.tsx index f3583b919..b7b208baf 100644 --- a/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/BorrowRateTooltip.tsx +++ b/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/BorrowRateTooltip.tsx @@ -21,25 +21,37 @@ const messages = { const rateType = 'borrow' as const const BorrowRateTooltipContent = ({ market }: { market: LlamaMarket }) => { - const { rewards, type: marketType, rates } = market - const { rate, averageRate, period } = useSnapshots(market, rateType) + const { + rewards, + type: marketType, + rates, + rates: { borrow: borrowRate, borrowTotalApy }, + assets: { + collateral: { rebasingYield, symbol: collateralSymbol }, + }, + } = market + const { averageRate, period } = useSnapshots(market, rateType) const poolRewards = useFilteredRewards(rewards, marketType, rateType) const extraIncentives = useMarketExtraIncentives(rateType, rates) + return ( {messages[marketType]} - {(poolRewards.length > 0 || extraIncentives.length > 0) && ( + {(poolRewards.length > 0 || extraIncentives.length > 0 || !!rebasingYield) && ( - - {formatPercent(rate)} - + {formatPercent(borrowRate)} + {!!rebasingYield && ( + + {formatPercent(rebasingYield)} + + )} )} - - {formatPercent(rate)} + + {formatPercent(borrowTotalApy)} {formatPercent(averageRate)} diff --git a/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/LendRateTooltip.tsx b/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/LendRateTooltip.tsx index 4f45fe2bc..d2f00a5b5 100644 --- a/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/LendRateTooltip.tsx +++ b/apps/main/src/llamalend/PageLlamaMarkets/cells/RateCell/LendRateTooltip.tsx @@ -16,17 +16,16 @@ 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 ( @@ -34,20 +33,23 @@ const LendRateTooltipContent = ({ market }: { market: LlamaMarket }) => { {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.`} - {yieldBearing && ( + {!!borrowed.rebasingYield && ( {t`The collateral of this market is yield bearing and offer extra yield.`} )} - - {formatPercent(rate)} - + {formatPercent(lendApr)} + {!!borrowed.rebasingYield && ( + + {formatPercent(borrowed.rebasingYield)} + + )} - - {formatPercent((rate ?? 0) + (lendCrvAprUnboosted ?? 0))} + + {formatPercent(lend)} {formatPercent(averageRate)} @@ -62,8 +64,8 @@ const LendRateTooltipContent = ({ market }: { market: LlamaMarket }) => { )} {lendCrvAprBoosted ? ( - - {formatPercent((rate ?? 0) + lendCrvAprBoosted)} + + {formatPercent((lendApr ?? 0) + lendCrvAprBoosted)} {formatPercent(maxBoostedAprAverage)} diff --git a/apps/main/src/llamalend/entities/llama-markets.ts b/apps/main/src/llamalend/entities/llama-markets.ts index 93194b3e7..d49e59509 100644 --- a/apps/main/src/llamalend/entities/llama-markets.ts +++ b/apps/main/src/llamalend/entities/llama-markets.ts @@ -30,6 +30,7 @@ export type AssetDetails = { usdPrice: number | null balance: number | null balanceUsd: number | null + rebasingYield: number | null } export type LlamaMarket = { @@ -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 @@ -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, @@ -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', @@ -163,6 +173,7 @@ const convertMintMarket = ( chain, balance: borrowed, balanceUsd: borrowed * stablecoin_price, + rebasingYield: null, }, collateral: { symbol: collateralSymbol, @@ -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( diff --git a/apps/main/src/loan/components/PageLoanCreate/Page.tsx b/apps/main/src/loan/components/PageLoanCreate/Page.tsx index b39627aae..f960f09a5 100644 --- a/apps/main/src/loan/components/PageLoanCreate/Page.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/Page.tsx @@ -41,15 +41,14 @@ const Page = (params: CollateralUrlParams) => { const { rFormType, rCollateralId } = parseCollateralParams(params) const { push } = useRouter() const { connectState, llamaApi: curve = null } = useConnection() - const pageLoaded = !isLoading(connectState) const rChainId = useChainId(params) const titleMapper = useTitleMapper() const { connect: connectWallet, provider } = useWallet() const [loaded, setLoaded] = useState(false) - const { llamma, displayName } = - useStore((state) => state.collaterals.collateralDatasMapper[rChainId]?.[rCollateralId]) ?? {} - const llammaId = llamma?.id ?? '' + const collateralDatasMapper = useStore((state) => state.collaterals.collateralDatasMapper[rChainId]) + const pageLoaded = !isLoading(connectState) + const { llamma, llamma: { id: llammaId = '' } = {}, displayName } = collateralDatasMapper?.[rCollateralId] ?? {} const formValues = useStore((state) => state.loanCreate.formValues) const loanExists = useStore((state) => state.loans.existsMapper[rCollateralId]?.loanExists) @@ -65,7 +64,7 @@ const Page = (params: CollateralUrlParams) => { const isAdvancedMode = useUserProfileStore((state) => state.isAdvancedMode) const maxSlippage = useUserProfileStore((state) => state.maxSlippage.crypto) - const isReady = !!llamma + const isReady = !!collateralDatasMapper const isValidRouterParams = !!rChainId && !!rCollateralId const isLeverage = rFormType === 'leverage' @@ -100,13 +99,14 @@ const Page = (params: CollateralUrlParams) => { fetchInitial(curve, isLeverage, llamma) void fetchLoanDetails(curve, llamma) setLoaded(true) - } else { - console.warn(`Collateral ${rCollateralId} not found for chain ${rChainId}. Redirecting to market list.`) + } else if (collateralDatasMapper) { + console.warn( + `Collateral ${rCollateralId} not found for chain ${rChainId}. Redirecting to market list.`, + collateralDatasMapper, + ) push(getCollateralListPathname(params)) } } - } else { - setLoaded(false) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [pageLoaded && curve && llamma]) diff --git a/packages/prices-api/src/llamalend/models.ts b/packages/prices-api/src/llamalend/models.ts index 0dce29b2e..a1fe90b6d 100644 --- a/packages/prices-api/src/llamalend/models.ts +++ b/packages/prices-api/src/llamalend/models.ts @@ -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 } diff --git a/packages/prices-api/src/llamalend/parsers.ts b/packages/prices-api/src/llamalend/parsers.ts index 363713e57..045eb45f0 100644 --- a/packages/prices-api/src/llamalend/parsers.ts +++ b/packages/prices-api/src/llamalend/parsers.ts @@ -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, }) diff --git a/packages/prices-api/src/llamalend/responses.ts b/packages/prices-api/src/llamalend/responses.ts index bfb59da59..3568da447 100644 --- a/packages/prices-api/src/llamalend/responses.ts +++ b/packages/prices-api/src/llamalend/responses.ts @@ -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 }[] diff --git a/tests/cypress/support/helpers/lending-mocks.ts b/tests/cypress/support/helpers/lending-mocks.ts index b8abd0213..fcf738db1 100644 --- a/tests/cypress/support/helpers/lending-mocks.ts +++ b/tests/cypress/support/helpers/lending-mocks.ts @@ -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 @@ -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 }, } }