Skip to content
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

"Implement separate netApy and borrow costs comparison for refinance" #3971

Merged
merged 2 commits into from
Jun 26, 2024
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
9 changes: 5 additions & 4 deletions features/productHub/views/ProductHubView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ import type {
import { useWalletManagement } from 'features/web3OnBoard/useConnection'
import { WithLoadingIndicator } from 'helpers/AppSpinner'
import { useSearchParams } from 'next/navigation'
import type { FC } from 'react'
import React, { Fragment, useMemo, useState } from 'react'
import type { ThemeUIStyleObject } from 'theme-ui'
import { Box } from 'theme-ui'

interface ProductHubViewProps {
export interface ProductHubViewProps<ProductHubItem> {
customSortByDefault?: (tableData: ProductHubItem[]) => ProductHubItem[]
databaseQuery?: ProductHubDatabaseQuery
dataParser?: (table: ProductHubItem[]) => ProductHubItem[]
Expand All @@ -54,7 +53,9 @@ interface ProductHubViewProps {
customFiltersOptions?: ProductHubCustomFiltersOptions
}

export const ProductHubView: FC<ProductHubViewProps> = ({
export function ProductHubView<
Props extends ProductHubViewProps<ProductHubItem> = ProductHubViewProps<ProductHubItem>,
>({
customSortByDefault,
databaseQuery,
dataParser = (_table) => _table,
Expand All @@ -77,7 +78,7 @@ export const ProductHubView: FC<ProductHubViewProps> = ({
url,
wrapperSx,
customFiltersOptions,
}) => {
}: Props) {
const { productHub: data } = usePreloadAppDataContext()
const table = useMemo(() => dataParser(data.table), [])

Expand Down
2 changes: 2 additions & 0 deletions features/refinance/components/RefinancePosition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const RefinancePosition = () => {
ltv,
borrowRate,
lendingProtocol,
netApy,
},
poolData: { maxLtv },
tx: { isTxSuccess },
Expand Down Expand Up @@ -55,6 +56,7 @@ export const RefinancePosition = () => {
liquidationPrice: new BigNumber(liquidationPrice),
collateral: new BigNumber(collateralTokenData.amount),
debt: new BigNumber(debtTokenData.amount),
netApy: new BigNumber(netApy),
}}
automations={automations}
/>
Expand Down
9 changes: 9 additions & 0 deletions features/refinance/components/RefinancePositionView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type RefinancePositionViewProps<Type extends RefinancePositionViewType> =
collateral: BigNumber
debt: BigNumber
liquidationPrice: BigNumber
netApy?: BigNumber
}
type: Type
automations: PortfolioPositionAutomations
Expand Down Expand Up @@ -106,6 +107,7 @@ export const RefinancePositionView = <Type extends RefinancePositionViewType>(
</RefinanceCardWrapper>
)
}

const {
primaryToken,
secondaryToken,
Expand Down Expand Up @@ -145,6 +147,7 @@ export const RefinancePositionView = <Type extends RefinancePositionViewType>(
...(poolData.borrowRateChange && {
borrowRateChange: `${formatDecimalAsPercent(poolData.borrowRateChange, { plus: true })}`,
}),
netApy: positionData?.netApy ? formatLtvDecimalAsPercent(positionData?.netApy) : 'N/A',
}

const isLoading = !positionData
Expand Down Expand Up @@ -195,6 +198,12 @@ export const RefinancePositionView = <Type extends RefinancePositionViewType>(
}),
tooltip: t('refinance.position.tooltips.borrow-rate'),
},
{
label: t('net-apy'),
value: formatted.netApy,
tooltip: t('refinance.position.tooltips.net-apy'),
isLoading,
},
{
label: t('system.protocol'),
value: <ProtocolLabel network={protocolData.network} protocol={protocolData.protocol} />,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const RefinanceHighlightedChangeSection = () => {

const {
poolData: { maxLtv },
position: { isShort, netApy },
position: { isShort, borrowRate },
form: {
state: { strategy, refinanceOption },
},
Expand All @@ -23,7 +23,7 @@ export const RefinanceHighlightedChangeSection = () => {
throw new Error('Refinance option not defined')
}

const borrowCost = new BigNumber(netApy)
const borrowCost = new BigNumber(borrowRate)

const afterBorrowCost = new BigNumber(strategy?.fee || zero)
const afterMaxLtv = new BigNumber(strategy?.maxLtv || zero)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getNetworkById } from 'blockchain/networks'
import { OmniProductType } from 'features/omni-kit/types'
import { ProductHubView } from 'features/productHub/views'
import type { ProductHubItem } from 'features/productHub/types'
import { ProductHubView, type ProductHubViewProps } from 'features/productHub/views'
import {
refinanceCustomProductHubFiltersOptions,
refinanceProductHubHiddenColumns,
Expand All @@ -16,6 +17,10 @@ import { RefinanceOptions } from 'features/refinance/types'
import { LendingProtocol } from 'lendingProtocols'
import React, { useCallback } from 'react'

export type ProductHubItemRefinance = ProductHubItem & {
netApy?: string
}

export const RefinanceProductTableStep = () => {
const {
metadata: { interestRates },
Expand Down Expand Up @@ -63,7 +68,7 @@ export const RefinanceProductTableStep = () => {
const network = getNetworkById(chainInfo.chainId)

return (
<ProductHubView
<ProductHubView<ProductHubViewProps<ProductHubItemRefinance>>
product={product}
customSortByDefault={(table) => table}
dataParser={(table) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getRefinanceInterestRatesInputParams,
getRefinanceTargetInterestRates,
} from 'features/refinance/helpers'
import { getNetAPY } from 'features/refinance/helpers/getBorrowRate'
import { getNetAPY } from 'features/refinance/helpers/getNetAPY'
import { useSdkSimulation } from 'features/refinance/hooks/useSdkSimulation'
import { WithLoadingIndicator } from 'helpers/AppSpinner'
import { WithErrorHandler } from 'helpers/errorHandlers/WithErrorHandler'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export function getNetAPY(currentLTV: string, borrowApy: string, supplyApy: stri
const netAPY = new BigNumber(multiple)
.times(supplyApy)
.minus(new BigNumber(multiple).minus(1).times(borrowApy))
.negated() // TODO: remember to remove this negation when enabling netAPY on the UI
.toString()

return netAPY
Expand Down
18 changes: 6 additions & 12 deletions features/refinance/helpers/getRefinanceProductHubDataParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { aaveLikeAprToApy } from 'handlers/product-hub/helpers'
import { moveItemsToFront } from 'helpers/moveItemsToFront'
import { LendingProtocol } from 'lendingProtocols'

import { getNetAPY } from './getBorrowRate'
import { getNetAPY } from './getNetAPY'

const availableLiquidityMapping = ({
table,
Expand Down Expand Up @@ -45,29 +45,23 @@ const borrowRateMapping = ({
currentLTV: string
}) =>
table.map((item) => {
// for Morho use PH rates
if (item.protocol === LendingProtocol.MorphoBlue) {
return item
}

const network = getNetworkByName(item.network)

const customCollateralRates = interestRates[network.id]?.[item.protocol]?.[item.primaryToken]
const customDebtRates = interestRates[network.id]?.[item.protocol]?.[item.secondaryToken]

// there are no rates so not possible to calculate apys
if (!customCollateralRates || !customDebtRates) {
return item
}

const borrowRate = getNetAPY(
currentLTV,
aaveLikeAprToApy(customDebtRates.borrowVariable),
aaveLikeAprToApy(customCollateralRates.lendVariable),
)
const borrowApy = aaveLikeAprToApy(customDebtRates.borrowVariable)
const lendApy = aaveLikeAprToApy(customCollateralRates.lendVariable)
const netApy = getNetAPY(currentLTV, borrowApy, lendApy)

return {
...item,
fee: borrowRate,
netApy,
}
})

Expand Down
8 changes: 7 additions & 1 deletion features/refinance/hooks/useSimulationPositionData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { useRefinanceContext } from 'features/refinance/contexts'
import type { RefinancePositionViewType } from 'features/refinance/types'

export const useSimulationPositionData = () => {
const { simulation } = useRefinanceContext()
const {
simulation,
form: {
state: { strategy },
},
} = useRefinanceContext()

if (simulation == null) {
return undefined
Expand Down Expand Up @@ -49,6 +54,7 @@ export const useSimulationPositionData = () => {
liquidationPrice: new BigNumber(liquidationPrice),
collateral: new BigNumber(targetPosition.collateralAmount.amount),
debt: new BigNumber(targetPosition.debtAmount.amount),
netApy: strategy?.netApy ? new BigNumber(strategy?.netApy) : undefined,
}

return positionData
Expand Down
4 changes: 2 additions & 2 deletions features/refinance/state/refinanceFormReducto.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { FormActionsReset } from 'features/omni-kit/state'
import type { ProductHubItem } from 'features/productHub/types'
import type { ProductHubItemRefinance } from 'features/refinance/components/steps'
import type { RefinanceOptions } from 'features/refinance/types'
import type { ReductoActions } from 'helpers/useReducto'

Expand All @@ -10,7 +10,7 @@ export type DpmRefinanceFormState = {

export interface RefinanceFormState {
refinanceOption?: RefinanceOptions
strategy?: ProductHubItem // strip to bare minimum during clean up
strategy?: ProductHubItemRefinance // strip to bare minimum during clean up
dpm?: DpmRefinanceFormState
hasSimilarPosition?: boolean
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function getRawPositionDetails(
RiskRatio.TYPE.LTV,
)

const borrowRate = calculations.netBorrowCostPercentage
const borrowRate = calculations.debtVariableBorrowRate
const maxRiskRatio = new RiskRatio(
onChainPositionData.category.maxLoanToValue,
RiskRatio.TYPE.LTV,
Expand Down
3 changes: 2 additions & 1 deletion public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -3785,7 +3785,8 @@
},
"tooltips": {
"max-ltv": "The Max Loan to Value indicates the amount that can be borrowed to the value of the collateral.",
"borrow-rate": "This borrow rate is the net APY of your position based on your current LTV. This is taking any supply APY into account, and borrow APY, and using your current LTV to determine the net APY you are paying (or receiving when positive) on your net value.",
"borrow-rate": "The borrow rate represents how much your debt will increase in one year at the current market utilization. This rate is variable, changing with utilization of the pool.",
"net-apy": "The Net APY of your position is based on your current LTV. This is taking any supply APY into account, and borrow APY, and using your current LTV to determine the net APY you are paying (or receiving when positive) on your net value.",
"automations": "This indicates which automation features are available for you on this position."
}
},
Expand Down
Loading