From c67126d1d93d9d51bd3c9e7e0a70ded227c3d455 Mon Sep 17 00:00:00 2001 From: Pearce Date: Wed, 19 Nov 2025 23:07:27 +0100 Subject: [PATCH 1/4] refactor: mint markets utils method for leverage and deleverage for each versions --- .../PageLoanCreate/LoanFormCreate/index.tsx | 5 +++-- .../src/loan/components/PageLoanCreate/Page.tsx | 4 ++-- .../src/loan/components/PageLoanCreate/index.tsx | 5 +++-- .../src/loan/components/PageLoanCreate/utils.ts | 5 ----- .../PageLoanManage/LoanDeleverage/index.tsx | 10 +++------- .../src/loan/components/PageLoanManage/Page.tsx | 4 ++-- .../src/loan/components/PageLoanManage/index.tsx | 4 ++-- .../src/loan/components/PageLoanManage/utils.ts | 7 +------ apps/main/src/loan/utils/leverage.ts | 16 ++++++++++++++++ 9 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 apps/main/src/loan/utils/leverage.ts diff --git a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx index 144b1032bc..f1be73eb75 100644 --- a/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/LoanFormCreate/index.tsx @@ -9,13 +9,14 @@ import DialogHealthLeverageWarning from '@/loan/components/PageLoanCreate/LoanFo import type { FormStatus, FormValues, PageLoanCreateProps, StepKey } from '@/loan/components/PageLoanCreate/types' import { StyledInpChip } from '@/loan/components/PageLoanManage/styles' import type { FormEstGas } from '@/loan/components/PageLoanManage/types' -import { DEFAULT_FORM_EST_GAS, DEFAULT_HEALTH_MODE, hasDeleverage } from '@/loan/components/PageLoanManage/utils' +import { DEFAULT_FORM_EST_GAS, DEFAULT_HEALTH_MODE } from '@/loan/components/PageLoanManage/utils' import { DEFAULT_WALLET_BALANCES } from '@/loan/constants' import networks from '@/loan/networks' import { DEFAULT_FORM_STATUS } from '@/loan/store/createLoanCollateralIncreaseSlice' import useStore from '@/loan/store/useStore' import { CollateralAlert, LlamaApi, Llamma } from '@/loan/types/loan.types' import { curveProps } from '@/loan/utils/helpers' +import { hasV1Deleverage } from '@/loan/utils/leverage' import { getStepStatus, getTokenName } from '@/loan/utils/utilsLoan' import { getLoanManagePathname } from '@/loan/utils/utilsRouter' import Accordion from '@ui/Accordion' @@ -437,7 +438,7 @@ const LoanCreate = ({

{t`You can leverage your collateral up to 9x. This has the effect of repeat trading crvUSD to collateral and depositing to maximize your collateral position. Essentially, all borrowed crvUSD is utilized to purchase more collateral.`}

{t`Be careful, if the collateral price dips, you would need to repay the entire amount to reclaim your initial position.`}

- {!hasDeleverage(llamma) && ( + {!hasV1Deleverage(llamma) && (

{t`WARNING: The corresponding deleverage button is also not yet available.`}

)}
diff --git a/apps/main/src/loan/components/PageLoanCreate/Page.tsx b/apps/main/src/loan/components/PageLoanCreate/Page.tsx index 3764384757..abbf80bf12 100644 --- a/apps/main/src/loan/components/PageLoanCreate/Page.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/Page.tsx @@ -11,12 +11,12 @@ import { useLoanExists } from '@/llamalend/queries/loan-exists' import ChartOhlcWrapper from '@/loan/components/ChartOhlcWrapper' import { MarketInformationComp } from '@/loan/components/MarketInformationComp' import LoanCreate from '@/loan/components/PageLoanCreate/index' -import { hasLeverage } from '@/loan/components/PageLoanCreate/utils' import { useMintMarket } from '@/loan/entities/mint-markets' import { useMarketDetails } from '@/loan/hooks/useMarketDetails' import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import { type CollateralUrlParams, type LlamaApi, Llamma } from '@/loan/types/loan.types' +import { hasV1Leverage } from '@/loan/utils/leverage' import { getTokenName } from '@/loan/utils/utilsLoan' import { getLoanCreatePathname, @@ -136,7 +136,7 @@ const Page = () => { // redirect if form is leverage but no leverage option useEffect(() => { - if (market && rFormType === 'leverage' && !hasLeverage(market)) { + if (market && rFormType === 'leverage' && !hasV1Leverage(market)) { push(getLoanCreatePathname(params, market.id)) } }, [loaded, rFormType, market, push, params]) diff --git a/apps/main/src/loan/components/PageLoanCreate/index.tsx b/apps/main/src/loan/components/PageLoanCreate/index.tsx index 0dc790c8b5..f3500440e8 100644 --- a/apps/main/src/loan/components/PageLoanCreate/index.tsx +++ b/apps/main/src/loan/components/PageLoanCreate/index.tsx @@ -4,11 +4,12 @@ import type { CreateLoanOptions } from '@/llamalend/features/borrow/queries/crea import type { OnBorrowFormUpdate } from '@/llamalend/features/borrow/types' import LoanFormCreate from '@/loan/components/PageLoanCreate/LoanFormCreate' import type { FormType, FormValues, PageLoanCreateProps } from '@/loan/components/PageLoanCreate/types' -import { DEFAULT_FORM_VALUES, hasLeverage } from '@/loan/components/PageLoanCreate/utils' +import { DEFAULT_FORM_VALUES } from '@/loan/components/PageLoanCreate/utils' import useCollateralAlert from '@/loan/hooks/useCollateralAlert' import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import { LlamaApi, Llamma } from '@/loan/types/loan.types' +import { hasV1Leverage } from '@/loan/utils/leverage' import { getLoanCreatePathname, getLoanManagePathname } from '@/loan/utils/utilsRouter' import Stack from '@mui/material/Stack' import { AppFormContentWrapper } from '@ui/AppForm' @@ -68,7 +69,7 @@ const LoanCreate = ({ [{ value: 'create' as const, label: t`Borrow` }] : [ { value: 'create' as const, label: t`Create Loan` }, - ...(hasLeverage(llamma) ? [{ value: 'leverage' as const, label: t`Leverage` }] : []), + ...(hasV1Leverage(llamma) ? [{ value: 'leverage' as const, label: t`Leverage` }] : []), ], [llamma, isBorrowUnifiedForm], ) diff --git a/apps/main/src/loan/components/PageLoanCreate/utils.ts b/apps/main/src/loan/components/PageLoanCreate/utils.ts index e56725d2eb..f16621e9a8 100644 --- a/apps/main/src/loan/components/PageLoanCreate/utils.ts +++ b/apps/main/src/loan/components/PageLoanCreate/utils.ts @@ -1,6 +1,5 @@ import type { FormDetailInfoLeverage, FormStatus, FormValues } from '@/loan/components/PageLoanCreate/types' import { DEFAULT_FORM_STATUS as FORM_STATUS } from '@/loan/components/PageLoanManage/utils' -import { Llamma } from '@/loan/types/loan.types' export const DEFAULT_DETAIL_INFO_LEVERAGE: FormDetailInfoLeverage = { collateral: '', @@ -30,7 +29,3 @@ export const DEFAULT_FORM_VALUES: FormValues = { debtError: '', n: null, } - -export function hasLeverage(llamma: Llamma | null) { - return !!llamma && llamma?.leverageZap !== '0x0000000000000000000000000000000000000000' -} diff --git a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx index 77911b41f9..59dc30231e 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx @@ -16,17 +16,13 @@ import type { FormDetailInfo, FormStatus, FormValues } from '@/loan/components/P import { DEFAULT_FORM_VALUES } from '@/loan/components/PageLoanManage/LoanDeleverage/utils' import { StyledDetailInfoWrapper, StyledInpChip } from '@/loan/components/PageLoanManage/styles' import type { PageLoanManageProps } from '@/loan/components/PageLoanManage/types' -import { - DEFAULT_DETAIL_INFO, - DEFAULT_FORM_EST_GAS, - DEFAULT_HEALTH_MODE, - hasDeleverage, -} from '@/loan/components/PageLoanManage/utils' +import { DEFAULT_DETAIL_INFO, DEFAULT_FORM_EST_GAS, DEFAULT_HEALTH_MODE } from '@/loan/components/PageLoanManage/utils' import { useUserLoanDetails } from '@/loan/hooks/useUserLoanDetails' import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import { LlamaApi, Llamma } from '@/loan/types/loan.types' import { curveProps } from '@/loan/utils/helpers' +import { hasV1Deleverage } from '@/loan/utils/leverage' import { getStepStatus, getTokenName } from '@/loan/utils/utilsLoan' import { getCollateralListPathname } from '@/loan/utils/utilsRouter' import AlertBox from '@ui/AlertBox' @@ -422,7 +418,7 @@ const LoanDeleverage = ({ {/* actions */} - {llamma && !hasDeleverage(llamma) ? ( + {llamma && !hasV1Deleverage(llamma) ? ( Deleverage is not available ) : ( diff --git a/apps/main/src/loan/components/PageLoanManage/Page.tsx b/apps/main/src/loan/components/PageLoanManage/Page.tsx index b89f5ac7b0..8615aaf124 100644 --- a/apps/main/src/loan/components/PageLoanManage/Page.tsx +++ b/apps/main/src/loan/components/PageLoanManage/Page.tsx @@ -13,7 +13,6 @@ import ChartOhlcWrapper from '@/loan/components/ChartOhlcWrapper' import { MarketInformationComp } from '@/loan/components/MarketInformationComp' import LoanMange from '@/loan/components/PageLoanManage/index' import type { FormType } from '@/loan/components/PageLoanManage/types' -import { hasDeleverage } from '@/loan/components/PageLoanManage/utils' import { useMintMarket } from '@/loan/entities/mint-markets' import { useLoanPositionDetails } from '@/loan/hooks/useLoanPositionDetails' import { useMarketDetails } from '@/loan/hooks/useMarketDetails' @@ -21,6 +20,7 @@ import { useUserLoanDetails } from '@/loan/hooks/useUserLoanDetails' import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import type { CollateralUrlParams } from '@/loan/types/loan.types' +import { hasV1Deleverage } from '@/loan/utils/leverage' import { getLoanCreatePathname, parseCollateralParams, useChainId } from '@/loan/utils/utilsRouter' import { isChain } from '@curvefi/prices-api' import Stack from '@mui/material/Stack' @@ -121,7 +121,7 @@ const Page = () => { // redirect if form is deleverage but no deleverage option useEffect(() => { - if (market && rFormType === 'deleverage' && !hasDeleverage(market)) { + if (market && rFormType === 'deleverage' && !hasV1Deleverage(market)) { push(getLoanCreatePathname(params, market.id)) } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/main/src/loan/components/PageLoanManage/index.tsx b/apps/main/src/loan/components/PageLoanManage/index.tsx index c0b16f0d3e..620451c132 100644 --- a/apps/main/src/loan/components/PageLoanManage/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/index.tsx @@ -11,7 +11,7 @@ import type { LoanFormType, PageLoanManageProps, } from '@/loan/components/PageLoanManage/types' -import { hasDeleverage } from '@/loan/components/PageLoanManage/utils' +import { hasV1Deleverage } from '@/loan/utils/leverage' import { getLoanManagePathname } from '@/loan/utils/utilsRouter' import Stack from '@mui/material/Stack' import { AppFormContentWrapper } from '@ui/AppForm' @@ -42,7 +42,7 @@ const LoanManage = ({ curve, isReady, llamma, llammaId, params, rChainId, rColla const tabs: TabOption[] = [ { value: 'loan' as const, label: t`Loan` }, { value: 'collateral' as const, label: t`Collateral` }, - ...(hasDeleverage(llamma) ? [{ value: 'deleverage' as const, label: t`Delever` }] : []), + ...(hasV1Deleverage(llamma) ? [{ value: 'deleverage' as const, label: t`Delever` }] : []), ] type SubTab = LoanFormType | CollateralFormType diff --git a/apps/main/src/loan/components/PageLoanManage/utils.ts b/apps/main/src/loan/components/PageLoanManage/utils.ts index 7de4b8dd15..d1f23de0f0 100644 --- a/apps/main/src/loan/components/PageLoanManage/utils.ts +++ b/apps/main/src/loan/components/PageLoanManage/utils.ts @@ -1,6 +1,5 @@ -import { zeroAddress } from 'viem' import { FormDetailInfo, FormEstGas, FormStatus } from '@/loan/components/PageLoanManage/types' -import { Llamma, HealthMode, UserWalletBalances } from '@/loan/types/loan.types' +import { HealthMode, UserWalletBalances } from '@/loan/types/loan.types' export const DEFAULT_HEALTH_MODE: HealthMode = { percent: '', @@ -36,7 +35,3 @@ export const DEFAULT_USER_WALLET_BALANCES: UserWalletBalances = { stablecoin: '0', error: '', } - -export function hasDeleverage(llamma: Llamma | null) { - return !!llamma && llamma?.deleverageZap !== zeroAddress -} diff --git a/apps/main/src/loan/utils/leverage.ts b/apps/main/src/loan/utils/leverage.ts new file mode 100644 index 0000000000..01620c7920 --- /dev/null +++ b/apps/main/src/loan/utils/leverage.ts @@ -0,0 +1,16 @@ +import { zeroAddress } from 'viem' +import type { Llamma } from '@/loan/types/loan.types' + +/** + * Mint market version with id < 6 is using v1 (leverageZap) + * Mint market with id >= 6 is using v2 leverage + */ +export type MintMarketVersion = 'v1' | 'v2' + +export const hasV1Leverage = (llamma: Llamma | null) => llamma?.leverageZap !== zeroAddress +export const hasV2Leverage = (llamma: Llamma | null) => !!llamma?.leverageV2.hasLeverage() +export const hasV1Deleverage = (llamma: Llamma | null) => llamma?.deleverageZap !== zeroAddress + +export const hasLeverage = (llamma: Llamma | null) => hasV1Leverage(llamma) || hasV2Leverage(llamma) +// hasV2Leverage works for deleverage as well +export const hasDeleverage = (llamma: Llamma | null) => hasV1Deleverage(llamma) || hasV2Leverage(llamma) From 6d5672298c9b3a79bc588bde665784e1ea216e4a Mon Sep 17 00:00:00 2001 From: Pearce Date: Thu, 20 Nov 2025 19:09:29 +0100 Subject: [PATCH 2/4] feat: enhance deleverage functionality with V2 leverage for new mint markets --- apps/main/src/loan/lib/apiCrvusd.ts | 170 +++++++++++++++++++++----- apps/main/src/loan/utils/utilsLoan.ts | 10 ++ 2 files changed, 150 insertions(+), 30 deletions(-) diff --git a/apps/main/src/loan/lib/apiCrvusd.ts b/apps/main/src/loan/lib/apiCrvusd.ts index 800e3134a9..ade835e0ca 100644 --- a/apps/main/src/loan/lib/apiCrvusd.ts +++ b/apps/main/src/loan/lib/apiCrvusd.ts @@ -4,6 +4,7 @@ import networks from '@/loan/networks' import type { LiqRange, MaxRecvLeverage, Provider } from '@/loan/store/types' import { ChainId, LlamaApi, Llamma, UserLoanDetails } from '@/loan/types/loan.types' import { fulfilledValue, getErrorMessage, log } from '@/loan/utils/helpers' +import { hasV2Leverage } from '@/loan/utils/leverage' import { getChartBandBalancesData, getIsUserCloseToLiquidation, @@ -14,6 +15,7 @@ import { } from '@/loan/utils/utilsCurvejs' import type { TGas } from '@curvefi/llamalend-api/lib/interfaces' import { waitForTransaction, waitForTransactions } from '@ui-kit/lib/ethers' +import { getLeverageV2RepayArgs, isHigherThanMaxSlippage } from '../utils/utilsLoan' export const network = { 1: { @@ -953,9 +955,26 @@ const loanDeleverage = { estGas: async (activeKey: string, llamma: Llamma, collateral: string, maxSlippage: string) => { log('estGas', llamma.collateralSymbol, collateral, maxSlippage) const resp = { activeKey, estimatedGas: initialGas, error: '' } + const slippage = Number(maxSlippage) || 0 try { - resp.estimatedGas = await llamma.deleverage.estimateGas.repay(collateral, +maxSlippage) + if (hasV2Leverage(llamma)) { + const repayArgs = getLeverageV2RepayArgs(collateral) + await llamma.leverageV2.repayExpectedBorrowed( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + slippage, + ) + resp.estimatedGas = await llamma.leverageV2.estimateGas.repay( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + slippage, + ) + } else { + resp.estimatedGas = await llamma.deleverage.estimateGas.repay(collateral, slippage) + } return resp } catch (error) { console.error(error) @@ -988,36 +1007,110 @@ const loanDeleverage = { } try { - // check if deleverage is available - const deleverageCollateral = +userState.collateral > 0 ? userState.collateral : collateral - if (+deleverageCollateral > 0) { - resp.isAvailable = await llamma.deleverage.isAvailable(deleverageCollateral) - } + const slippage = Number(maxSlippage) || 0 + if (hasV2Leverage(llamma)) { + const repayArgs = getLeverageV2RepayArgs(collateral) + const availabilityCollateral = +userState.collateral > 0 ? userState.collateral : repayArgs.stateCollateral + const availabilityArgs = getLeverageV2RepayArgs(availabilityCollateral) + + if (+availabilityArgs.stateCollateral > 0) { + resp.isAvailable = await llamma.leverageV2.repayIsAvailable( + availabilityArgs.stateCollateral, + availabilityArgs.userCollateral, + availabilityArgs.userBorrowed, + address, + ) + } - if (resp.isAvailable && +collateral > 0) { - resp.isFullRepayment = await llamma.deleverage.isFullRepayment(collateral) - - const [{ stablecoins, routeIdx }, priceImpact] = await Promise.all([ - llamma.deleverage.repayStablecoins(collateral), - llamma.deleverage.priceImpact(collateral), - ]) - resp.receiveStablecoin = stablecoins - resp.routeName = await llamma.deleverage.getRouteName(routeIdx) - resp.priceImpact = priceImpact - resp.isHighImpact = +priceImpact > 0 && +maxSlippage > 0 ? +priceImpact > +maxSlippage : false - - if (!resp.isFullRepayment) { - const [healthFullResult, healthNotFullResult, bandsResult, pricesResult] = await Promise.allSettled([ - llamma.deleverage.repayHealth(collateral, true, address), - llamma.deleverage.repayHealth(collateral, false, address), - llamma.deleverage.repayBands(collateral, address), - llamma.deleverage.repayPrices(collateral, address), - ]) + if (resp.isAvailable && +repayArgs.stateCollateral > 0) { + const repayExpected = await llamma.leverageV2.repayExpectedBorrowed( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + slippage, + ) + resp.receiveStablecoin = repayExpected.totalBorrowed + resp.isFullRepayment = await llamma.leverageV2.repayIsFull( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + address, + ) + + resp.priceImpact = await llamma.leverageV2.repayPriceImpact( + repayArgs.stateCollateral, + repayArgs.userCollateral, + ) + resp.isHighImpact = isHigherThanMaxSlippage(resp.priceImpact, maxSlippage) + resp.routeName = 'ODOS' + + if (!resp.isFullRepayment) { + const [healthFullResult, healthNotFullResult, bandsResult, pricesResult] = await Promise.allSettled([ + llamma.leverageV2.repayHealth( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + true, + address, + ), + llamma.leverageV2.repayHealth( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + false, + address, + ), + llamma.leverageV2.repayBands( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + address, + ), + llamma.leverageV2.repayPrices( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + address, + ), + ]) + + resp.healthFull = fulfilledValue(healthFullResult) ?? '' + resp.healthNotFull = fulfilledValue(healthNotFullResult) ?? '' + resp.bands = reverseBands(fulfilledValue(bandsResult) ?? [0, 0]) + resp.prices = fulfilledValue(pricesResult) ?? [] + } + } + } else { + const deleverageCollateral = +userState.collateral > 0 ? userState.collateral : collateral + if (+deleverageCollateral > 0) { + resp.isAvailable = await llamma.deleverage.isAvailable(deleverageCollateral) + } + + if (resp.isAvailable && +collateral > 0) { + resp.isFullRepayment = await llamma.deleverage.isFullRepayment(collateral) - resp.healthFull = fulfilledValue(healthFullResult) ?? '' - resp.healthNotFull = fulfilledValue(healthNotFullResult) ?? '' - resp.bands = reverseBands(fulfilledValue(bandsResult) ?? [0, 0]) - resp.prices = fulfilledValue(pricesResult) ?? [] + const [{ stablecoins, routeIdx }, priceImpact] = await Promise.all([ + llamma.deleverage.repayStablecoins(collateral), + llamma.deleverage.priceImpact(collateral), + ]) + resp.receiveStablecoin = stablecoins + resp.routeName = await llamma.deleverage.getRouteName(routeIdx) + resp.priceImpact = priceImpact + resp.isHighImpact = isHigherThanMaxSlippage(priceImpact, maxSlippage) + + if (!resp.isFullRepayment) { + const [healthFullResult, healthNotFullResult, bandsResult, pricesResult] = await Promise.allSettled([ + llamma.deleverage.repayHealth(collateral, true, address), + llamma.deleverage.repayHealth(collateral, false, address), + llamma.deleverage.repayBands(collateral, address), + llamma.deleverage.repayPrices(collateral, address), + ]) + + resp.healthFull = fulfilledValue(healthFullResult) ?? '' + resp.healthNotFull = fulfilledValue(healthNotFullResult) ?? '' + resp.bands = reverseBands(fulfilledValue(bandsResult) ?? [0, 0]) + resp.prices = fulfilledValue(pricesResult) ?? [] + } } } @@ -1031,9 +1124,26 @@ const loanDeleverage = { repay: async (activeKey: string, provider: Provider, llamma: Llamma, collateral: string, maxSlippage: string) => { log('deleverageRepay', llamma.collateralSymbol, collateral, maxSlippage) const resp = { activeKey, hash: '', error: '' } + const slippage = Number(maxSlippage) || 0 try { - resp.hash = await llamma.deleverage.repay(collateral, +maxSlippage) + if (hasV2Leverage(llamma)) { + const repayArgs = getLeverageV2RepayArgs(collateral) + await llamma.leverageV2.repayExpectedBorrowed( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + slippage, + ) + resp.hash = await llamma.leverageV2.repay( + repayArgs.stateCollateral, + repayArgs.userCollateral, + repayArgs.userBorrowed, + slippage, + ) + } else { + resp.hash = await llamma.deleverage.repay(collateral, slippage) + } await waitForTransaction(resp.hash, provider) return resp } catch (error) { diff --git a/apps/main/src/loan/utils/utilsLoan.ts b/apps/main/src/loan/utils/utilsLoan.ts index d1b48ba96a..591d97ca5f 100644 --- a/apps/main/src/loan/utils/utilsLoan.ts +++ b/apps/main/src/loan/utils/utilsLoan.ts @@ -14,3 +14,13 @@ export function getTokenName(llamma: Llamma | null | undefined) { const [stablecoin, collateral] = llamma?.coins ?? ['', ''] return { stablecoin, collateral } } + +export const getLeverageV2RepayArgs = (stateCollateral: string) => ({ + stateCollateral: stateCollateral, + // amount for repay/deleverage only from collateral for now + userCollateral: '0', + userBorrowed: '0', +}) + +export const isHigherThanMaxSlippage = (priceImpact: string, maxSlippage: string) => + +priceImpact > 0 && +maxSlippage > 0 ? +priceImpact > +maxSlippage : false From 6379276764592ea618c1cb50b952c643472285e4 Mon Sep 17 00:00:00 2001 From: Pearce Date: Thu, 20 Nov 2025 19:09:52 +0100 Subject: [PATCH 3/4] feat: enable deleverage for new mint markets --- .../loan/components/PageLoanManage/LoanDeleverage/index.tsx | 4 ++-- apps/main/src/loan/components/PageLoanManage/Page.tsx | 4 ++-- apps/main/src/loan/components/PageLoanManage/index.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx index 59dc30231e..0ee68aea58 100644 --- a/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/LoanDeleverage/index.tsx @@ -22,7 +22,7 @@ import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import { LlamaApi, Llamma } from '@/loan/types/loan.types' import { curveProps } from '@/loan/utils/helpers' -import { hasV1Deleverage } from '@/loan/utils/leverage' +import { hasDeleverage } from '@/loan/utils/leverage' import { getStepStatus, getTokenName } from '@/loan/utils/utilsLoan' import { getCollateralListPathname } from '@/loan/utils/utilsRouter' import AlertBox from '@ui/AlertBox' @@ -418,7 +418,7 @@ const LoanDeleverage = ({ {/* actions */} - {llamma && !hasV1Deleverage(llamma) ? ( + {llamma && !hasDeleverage(llamma) ? ( Deleverage is not available ) : ( diff --git a/apps/main/src/loan/components/PageLoanManage/Page.tsx b/apps/main/src/loan/components/PageLoanManage/Page.tsx index 8615aaf124..7ff328dd5e 100644 --- a/apps/main/src/loan/components/PageLoanManage/Page.tsx +++ b/apps/main/src/loan/components/PageLoanManage/Page.tsx @@ -20,7 +20,7 @@ import { useUserLoanDetails } from '@/loan/hooks/useUserLoanDetails' import networks from '@/loan/networks' import useStore from '@/loan/store/useStore' import type { CollateralUrlParams } from '@/loan/types/loan.types' -import { hasV1Deleverage } from '@/loan/utils/leverage' +import { hasDeleverage } from '@/loan/utils/leverage' import { getLoanCreatePathname, parseCollateralParams, useChainId } from '@/loan/utils/utilsRouter' import { isChain } from '@curvefi/prices-api' import Stack from '@mui/material/Stack' @@ -121,7 +121,7 @@ const Page = () => { // redirect if form is deleverage but no deleverage option useEffect(() => { - if (market && rFormType === 'deleverage' && !hasV1Deleverage(market)) { + if (market && rFormType === 'deleverage' && !hasDeleverage(market)) { push(getLoanCreatePathname(params, market.id)) } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/main/src/loan/components/PageLoanManage/index.tsx b/apps/main/src/loan/components/PageLoanManage/index.tsx index 620451c132..e29d4768f5 100644 --- a/apps/main/src/loan/components/PageLoanManage/index.tsx +++ b/apps/main/src/loan/components/PageLoanManage/index.tsx @@ -11,7 +11,7 @@ import type { LoanFormType, PageLoanManageProps, } from '@/loan/components/PageLoanManage/types' -import { hasV1Deleverage } from '@/loan/utils/leverage' +import { hasDeleverage } from '@/loan/utils/leverage' import { getLoanManagePathname } from '@/loan/utils/utilsRouter' import Stack from '@mui/material/Stack' import { AppFormContentWrapper } from '@ui/AppForm' @@ -42,7 +42,7 @@ const LoanManage = ({ curve, isReady, llamma, llammaId, params, rChainId, rColla const tabs: TabOption[] = [ { value: 'loan' as const, label: t`Loan` }, { value: 'collateral' as const, label: t`Collateral` }, - ...(hasV1Deleverage(llamma) ? [{ value: 'deleverage' as const, label: t`Delever` }] : []), + ...(hasDeleverage(llamma) ? [{ value: 'deleverage' as const, label: t`Delever` }] : []), ] type SubTab = LoanFormType | CollateralFormType From 22a847f34e7e9ab5b5f2866d4628fd2ded787deb Mon Sep 17 00:00:00 2001 From: Pearce Date: Thu, 20 Nov 2025 19:10:36 +0100 Subject: [PATCH 4/4] refactor: add RouteAggregator enum for mint markets --- apps/main/src/loan/constants.ts | 8 ++++++++ apps/main/src/loan/lib/apiCrvusd.ts | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/main/src/loan/constants.ts b/apps/main/src/loan/constants.ts index 897c5fd1a8..02ad04f0e9 100644 --- a/apps/main/src/loan/constants.ts +++ b/apps/main/src/loan/constants.ts @@ -37,3 +37,11 @@ export const DEFAULT_WALLET_BALANCES: UserWalletBalances = { collateral: '0', error: '', } + +export enum RouteAggregator { + Odos = 'odos', +} + +export const ROUTE_AGGREGATOR_LABELS: Record = { + [RouteAggregator.Odos]: 'Odos', +} diff --git a/apps/main/src/loan/lib/apiCrvusd.ts b/apps/main/src/loan/lib/apiCrvusd.ts index ade835e0ca..5edd8df6de 100644 --- a/apps/main/src/loan/lib/apiCrvusd.ts +++ b/apps/main/src/loan/lib/apiCrvusd.ts @@ -15,6 +15,7 @@ import { } from '@/loan/utils/utilsCurvejs' import type { TGas } from '@curvefi/llamalend-api/lib/interfaces' import { waitForTransaction, waitForTransactions } from '@ui-kit/lib/ethers' +import { ROUTE_AGGREGATOR_LABELS, RouteAggregator } from '../constants' import { getLeverageV2RepayArgs, isHigherThanMaxSlippage } from '../utils/utilsLoan' export const network = { @@ -1042,7 +1043,7 @@ const loanDeleverage = { repayArgs.userCollateral, ) resp.isHighImpact = isHigherThanMaxSlippage(resp.priceImpact, maxSlippage) - resp.routeName = 'ODOS' + resp.routeName = ROUTE_AGGREGATOR_LABELS[RouteAggregator.Odos] if (!resp.isFullRepayment) { const [healthFullResult, healthNotFullResult, bandsResult, pricesResult] = await Promise.allSettled([