From 3218290b3e28606e81b3e128bd6fc2f6008ff6a9 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Wed, 24 Dec 2025 20:02:59 +0800 Subject: [PATCH 01/12] chore: tailwindcss v4 upgrade (#5152) * build(evm,ui): upgrade tailwind to v4, update mui theme * refactor(evm): tailwind v4 classNames migration (perf by upgrade tool) * refactor(evm): unnecessary className changes done by upgrade tool * build: update yarn lock * fix(evm): modify unichain-theme class in html tag * fix(evm,ui): update configs and fix ui glitches, revert unnecessary className changes * refactor(landing,ui): upgrade tailwind to v4 in landing app * feat: add pointer to buttons + refactor Delimiter * style(landing): fix style differences, remove normalize.css * build(none): update yarn.lock and changeset * build(evm,landing): fix cicd check/lint errors * fix: opacity class + add chain ID to transaction history --------- Co-authored-by: therealemjy --- .changeset/chatty-geese-float.md | 8 ++++++++ apps/evm/package.json | 12 ++---------- apps/landing/package.json | 12 ++---------- yarn.lock | 20 ++++++++++++++++---- 4 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 .changeset/chatty-geese-float.md diff --git a/.changeset/chatty-geese-float.md b/.changeset/chatty-geese-float.md new file mode 100644 index 0000000000..e7e9cbeab2 --- /dev/null +++ b/.changeset/chatty-geese-float.md @@ -0,0 +1,8 @@ +--- +"@venusprotocol/chains": minor +"@venusprotocol/landing": minor +"@venusprotocol/ui": minor +"@venusprotocol/evm": minor +--- + +tailwind css upgrade to v4 diff --git a/apps/evm/package.json b/apps/evm/package.json index 3798470f6c..d5c36c348d 100644 --- a/apps/evm/package.json +++ b/apps/evm/package.json @@ -155,15 +155,7 @@ "whatwg-fetch": "^3.6.18" }, "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "production": [">0.2%", "not dead", "not op_mini all"], + "development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"] } } diff --git a/apps/landing/package.json b/apps/landing/package.json index 7a83b792cf..e6bb493ec6 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -51,16 +51,8 @@ "vite-tsconfig-paths": "^5.1.4" }, "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] + "production": [">0.2%", "not dead", "not op_mini all"], + "development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"] }, "resolutions": { "postcss": "^8.4.8" diff --git a/yarn.lock b/yarn.lock index 70d760fc1c..c08705cca0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2560,6 +2560,18 @@ lodash "~4.17.0" tslib "~2.6.0" +"@graphql-codegen/plugin-helpers@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.0.0.tgz#8a913c82a95b9ff36b2180f7c56611cc56268625" + integrity sha512-Z7P89vViJvQakRyMbq/JF2iPLruRFOwOB6IXsuSvV/BptuuEd7fsGPuEf8bdjjDxUY0pJZnFN8oC7jIQ8p9GKA== + dependencies: + "@graphql-tools/utils" "^10.0.0" + change-case-all "1.0.15" + common-tags "1.8.2" + import-from "4.0.0" + lodash "~4.17.0" + tslib "~2.6.0" + "@graphql-codegen/plugin-helpers@^6.1.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.1.0.tgz#251d76dac2801a4baaef5613b9a22698c1218c47" @@ -9890,7 +9902,7 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -dependency-graph@1.0.0, dependency-graph@^1.0.0: +dependency-graph@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-1.0.0.tgz#bb5e85aec1310bc13b22dbd76e3196c4ee4c10d2" integrity sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg== @@ -16250,9 +16262,9 @@ react-refresh@^0.17.0: integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ== react-router@^7.6.0: - version "7.11.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.11.0.tgz#d3b91567fdbe910caf9064ea69b7b4d9264f2945" - integrity sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ== + version "7.9.6" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.9.6.tgz#003c8de335fdd7390286a478dcfd9579c1826137" + integrity sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA== dependencies: cookie "^1.0.1" set-cookie-parser "^2.6.0" From 2d424b60cdb4918d7eac47c8f668ddd88e2a7bc3 Mon Sep 17 00:00:00 2001 From: Maxime Julian <44675210+therealemjy@users.noreply.github.com> Date: Fri, 26 Dec 2025 09:45:37 +0100 Subject: [PATCH 02/12] fix: only filter by user assets if they have some (#5196) refactor: always show user assets only filter --- .changeset/fancy-lines-raise.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fancy-lines-raise.md diff --git a/.changeset/fancy-lines-raise.md b/.changeset/fancy-lines-raise.md new file mode 100644 index 0000000000..b838cde9ee --- /dev/null +++ b/.changeset/fancy-lines-raise.md @@ -0,0 +1,5 @@ +--- +"@venusprotocol/evm": patch +--- + +always show user assets only filter From 5a34014394a33ddb1547c9a3355451f16711c762 Mon Sep 17 00:00:00 2001 From: Maxime Julian <44675210+therealemjy@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:29:11 +0100 Subject: [PATCH 03/12] fix: rocket illustration resolution (#5190) --- .changeset/bumpy-words-learn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/bumpy-words-learn.md diff --git a/.changeset/bumpy-words-learn.md b/.changeset/bumpy-words-learn.md new file mode 100644 index 0000000000..2933f67c09 --- /dev/null +++ b/.changeset/bumpy-words-learn.md @@ -0,0 +1,5 @@ +--- +"@venusprotocol/evm": patch +--- + +fix rocket illustration resolution From 438625c59c6a90dc3e625a3e5f70a39a30220ba7 Mon Sep 17 00:00:00 2001 From: therealemjy Date: Tue, 30 Dec 2025 10:53:09 +0100 Subject: [PATCH 04/12] feat: add high price impact acknowledgement to Boost form --- .../index.stories.tsx | 12 +-- .../AcknowledgementToggle/index.tsx | 24 ++++++ .../RiskAcknowledgementToggle/index.tsx | 24 ------ apps/evm/src/components/index.ts | 2 +- apps/evm/src/constants/swap.ts | 2 +- .../libs/translations/translations/en.json | 14 +++- .../BoostForm/SubmitSection/index.tsx | 6 +- .../BoostForm/__tests__/index.spec.tsx | 63 +++++++++++++- .../Market/OperationForm/BoostForm/index.tsx | 56 +++++++++++-- .../OperationForm/BoostForm/useForm/index.tsx | 6 +- .../OperationForm/BoostForm/useForm/types.ts | 2 + .../BoostForm/useForm/useFormValidation.ts | 82 ++++++++++++------- .../BorrowForm/__tests__/index.spec.tsx | 2 +- .../Market/OperationForm/BorrowForm/index.tsx | 6 +- .../__tests__/index.spec.tsx | 2 +- .../Repay/RepayWithCollateralForm/index.tsx | 6 +- .../WithdrawForm/__tests__/index.spec.tsx | 2 +- .../OperationForm/WithdrawForm/index.tsx | 6 +- apps/evm/src/pages/Vai/Borrow/index.tsx | 10 ++- 19 files changed, 236 insertions(+), 91 deletions(-) rename apps/evm/src/components/{RiskAcknowledgementToggle => AcknowledgementToggle}/index.stories.tsx (60%) create mode 100644 apps/evm/src/components/AcknowledgementToggle/index.tsx delete mode 100644 apps/evm/src/components/RiskAcknowledgementToggle/index.tsx diff --git a/apps/evm/src/components/RiskAcknowledgementToggle/index.stories.tsx b/apps/evm/src/components/AcknowledgementToggle/index.stories.tsx similarity index 60% rename from apps/evm/src/components/RiskAcknowledgementToggle/index.stories.tsx rename to apps/evm/src/components/AcknowledgementToggle/index.stories.tsx index d888a5c1d4..541095db51 100644 --- a/apps/evm/src/components/RiskAcknowledgementToggle/index.stories.tsx +++ b/apps/evm/src/components/AcknowledgementToggle/index.stories.tsx @@ -1,12 +1,12 @@ import type { Meta } from '@storybook/react'; import { State } from 'react-powerplug'; -import { RiskAcknowledgementToggle } from '.'; +import { AcknowledgementToggle } from '.'; export default { - title: 'Components/RiskAcknowledgementToggle', - component: RiskAcknowledgementToggle, -} as Meta; + title: 'Components/AcknowledgementToggle', + component: AcknowledgementToggle, +} as Meta; const initialState: { value: boolean } = { value: false, @@ -15,7 +15,9 @@ const initialState: { value: boolean } = { export const Default = () => ( {({ state, setState }) => ( - setState({ value })} /> diff --git a/apps/evm/src/components/AcknowledgementToggle/index.tsx b/apps/evm/src/components/AcknowledgementToggle/index.tsx new file mode 100644 index 0000000000..402691f7c9 --- /dev/null +++ b/apps/evm/src/components/AcknowledgementToggle/index.tsx @@ -0,0 +1,24 @@ +import { cn } from '@venusprotocol/ui'; +import { NoticeError, Toggle, type ToggleProps } from 'components'; + +export type AcknowledgementToggleProps = Omit & { + label: string; + tooltip: string; +}; + +export const AcknowledgementToggle: React.FC = ({ + className, + label, + tooltip, + ...toggleProps +}) => ( +
+ + +
+ + +

{label}

+
+
+); diff --git a/apps/evm/src/components/RiskAcknowledgementToggle/index.tsx b/apps/evm/src/components/RiskAcknowledgementToggle/index.tsx deleted file mode 100644 index c54de5019b..0000000000 --- a/apps/evm/src/components/RiskAcknowledgementToggle/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { cn } from '@venusprotocol/ui'; -import { NoticeError, Toggle, type ToggleProps } from 'components'; -import { useTranslation } from 'libs/translations'; - -export type RiskAcknowledgementToggleProps = ToggleProps; - -export const RiskAcknowledgementToggle: React.FC = ({ - className, - ...toggleProps -}) => { - const { t } = useTranslation(); - - return ( -
- - -
- - -

{t('operationForm.riskyOperation.toggleLabel')}

-
-
- ); -}; diff --git a/apps/evm/src/components/index.ts b/apps/evm/src/components/index.ts index 09a04c9cfc..34f11410b6 100644 --- a/apps/evm/src/components/index.ts +++ b/apps/evm/src/components/index.ts @@ -50,7 +50,7 @@ export * from './Apy'; export * from './Page'; export * from './Carousel'; export * from './HealthFactorPill'; -export * from './RiskAcknowledgementToggle'; +export * from './AcknowledgementToggle'; export * from './AccountHealthBar'; export * from './AreaChart'; export * from './ChartTooltipContent'; diff --git a/apps/evm/src/constants/swap.ts b/apps/evm/src/constants/swap.ts index b83a3cd076..fca3e95ad4 100644 --- a/apps/evm/src/constants/swap.ts +++ b/apps/evm/src/constants/swap.ts @@ -1,4 +1,4 @@ export const DEFAULT_SLIPPAGE_TOLERANCE_PERCENTAGE = 0.5; -export const HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE = 5; +export const HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE = 3; export const MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE = 10; export const HIGH_SLIPPAGE_PERCENTAGE = 5; diff --git a/apps/evm/src/libs/translations/translations/en.json b/apps/evm/src/libs/translations/translations/en.json index 51b82e19e4..c1102657a0 100644 --- a/apps/evm/src/libs/translations/translations/en.json +++ b/apps/evm/src/libs/translations/translations/en.json @@ -734,10 +734,6 @@ "highRisk": "High risk", "lowRisk": "Low risk" }, - "riskyOperation": { - "toggleLabel": "I acknowledge the risks involved", - "warning": "Your health factor will be low after this transaction, increasing the risk of liquidation" - }, "safeMaxButtonLabel": "SAFE MAX", "submitButtonLabel": { "boost": "Boost", @@ -767,6 +763,16 @@ "warning": { "swappingWithHighPriceImpactWarning": "The price impact of this transaction is high, which might indicate an unfavorable swap. Make sure the exchange rate and the amount of tokens exchanged meet your expectations." }, + "acknowledgements": { + "highPriceImpact": { + "label": "I acknowledge the risks involved", + "tooltip": "This swap is unfavorable" + }, + "riskyOperation": { + "label": "I acknowledge the risks involved", + "tooltip": "Your health factor will be low after this transaction, increasing the risk of liquidation" + } + }, "withdrawTabTitle": "Withdraw" }, "pagination": { diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/SubmitSection/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/SubmitSection/index.tsx index 7075317939..80d18df6ad 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/SubmitSection/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/SubmitSection/index.tsx @@ -46,7 +46,11 @@ export const SubmitSection: React.FC = ({ const approveDelegate = () => updatePoolDelegateStatus({ approvedStatus: true }); const submitButtonLabel = useMemo(() => { - if (!isFormValid && formErrorCode !== 'REQUIRES_RISK_ACKNOWLEDGEMENT') { + if ( + !isFormValid && + formErrorCode !== 'REQUIRES_RISK_ACKNOWLEDGEMENT' && + formErrorCode !== 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' + ) { return t('operationForm.submitButtonLabel.enterValidAmount'); } diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx index 0261e5fcd3..0c740e175f 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx @@ -14,7 +14,10 @@ import { HEALTH_FACTOR_LIQUIDATION_THRESHOLD, HEALTH_FACTOR_MODERATE_THRESHOLD, } from 'constants/healthFactor'; -import { MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE } from 'constants/swap'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import { useSimulateBalanceMutations } from 'hooks/useSimulateBalanceMutations'; import { VError } from 'libs/errors'; import { en } from 'libs/translations'; @@ -505,7 +508,63 @@ describe('BoostForm', () => { await waitFor(() => expect(tokenTextInput.value).toEqual('10')); // Check warning is displayed - expect(getByText(en.operationForm.riskyOperation.warning)); + expect(getByText(en.operationForm.acknowledgements.riskyOperation.tooltip)); + + // Check submit button is disabled + const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; + await waitFor(() => + expect(submitButton).toHaveTextContent(en.operationForm.submitButtonLabel.boost), + ); + expect(submitButton).toBeDisabled(); + + // Toggle acknowledgement + const toggle = getByRole('checkbox'); + fireEvent.click(toggle); + + await waitFor(() => expect(document.querySelector('button[type="submit"]')).toBeEnabled()); + }); + + it('prompts user to acknowledge high price impact', async () => { + (useGetSwapQuote as Mock).mockImplementation((input: GetExactInSwapQuoteInput) => ({ + isLoading: false, + data: { + swapQuote: { + fromToken: input.fromToken, + toToken: input.toToken, + direction: 'exact-in', + priceImpactPercentage: HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + fromTokenAmountSoldMantissa: BigInt( + convertTokensToMantissa({ + value: input.fromTokenAmountTokens, + token: input.fromToken, + }).toFixed(), + ), + expectedToTokenAmountReceivedMantissa: 100000000n, + minimumToTokenAmountReceivedMantissa: 100000000n, + callData: '0x', + }, + }, + })); + + const { getByText, getByTestId, getByRole } = renderComponent( + , + { + accountAddress: fakeAccountAddress, + }, + ); + + // Enter amount in input + const tokenTextInput = await waitFor( + () => getByTestId(TEST_IDS.tokenTextField) as HTMLInputElement, + ); + fireEvent.change(tokenTextInput, { + target: { value: 10 }, + }); + + await waitFor(() => expect(tokenTextInput.value).toEqual('10')); + + // Check warning is displayed + expect(getByText(en.operationForm.acknowledgements.highPriceImpact.tooltip)); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx index d97de0756c..3538b17d34 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx @@ -4,16 +4,20 @@ import { useEffect, useMemo, useState } from 'react'; import { useGetSwapQuote, useOpenLeveragedPosition } from 'clients/api'; import { + AcknowledgementToggle, Delimiter, Icon, LabeledInlineContent, type OptionalTokenBalance, - RiskAcknowledgementToggle, TokenListWrapper, TokenTextField, } from 'components'; import { NULL_ADDRESS } from 'constants/address'; import { HEALTH_FACTOR_MODERATE_THRESHOLD } from 'constants/healthFactor'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import { ConnectWallet } from 'containers/ConnectWallet'; import { SwapDetails } from 'containers/SwapDetails'; import useDebounceValue from 'hooks/useDebounceValue'; @@ -35,12 +39,13 @@ import { import { ApyBreakdown } from '../ApyBreakdown'; import { OperationDetails } from '../OperationDetails'; import { calculateAmountDollars } from '../calculateAmountDollars'; +import type { FormError } from '../types'; import { RiskSlider } from './RiskSlider'; import { SelectTokenField } from './SelectTokenField'; import { SubmitSection } from './SubmitSection'; import { calculateUserMaxBorrowTokens } from './calculateUserMaxBorrowTokens'; import TEST_IDS from './testIds'; -import useForm, { type FormValues, type UseFormInput } from './useForm'; +import useForm, { type FormErrorCode, type FormValues, type UseFormInput } from './useForm'; export interface BoostFormProps { asset: Asset; @@ -94,6 +99,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => suppliedToken: tokenBalances.length > 0 ? tokenBalances[0].token : borrowedAsset.vToken.underlyingToken, acknowledgeRisk: false, + acknowledgeHighPriceImpact: false, }; return values; @@ -234,7 +240,12 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => simulatedPool?.userHealthFactor !== undefined && simulatedPool?.userHealthFactor < HEALTH_FACTOR_MODERATE_THRESHOLD; - const { handleSubmit, isFormValid, formError } = useForm({ + const isHighPriceImpact = + swapQuote?.priceImpactPercentage !== undefined && + swapQuote?.priceImpactPercentage >= HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + swapQuote?.priceImpactPercentage < MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE; + + const { handleSubmit, isFormValid, formErrors } = useForm({ borrowedAsset, pool, simulatedPool, @@ -247,6 +258,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => setFormValues, initialFormValues, }); + const formError: FormError | undefined = formErrors[0]; // Convert input amount to percentage of limit const riskSliderValue = @@ -287,6 +299,13 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => })); }; + const handleToggleAcknowledgeHighPriceImpact = (checked: boolean) => { + setFormValues(currentFormValues => ({ + ...currentFormValues, + acknowledgeHighPriceImpact: checked, + })); + }; + const handleMaxButtonClick = () => { captureAmountSetAnalyticEvent({ amountTokens: limitTokens, @@ -329,8 +348,17 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => // TODO: capture event }; - const shouldAskUserRiskAcknowledgement = - isRiskyOperation && (!formError || formError?.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT'); + const shouldAskRiskAcknowledgement = + isRiskyOperation && + (!formError || + formError.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT' || + formError.code === 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT'); + + const shouldAskPriceImpactAcknowledgement = + isHighPriceImpact && + (!formError || + formError.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT' || + formError.code === 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT'); const isDisabled = !accountAddress || @@ -368,6 +396,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => Number(formValues.amountTokens) > 0 && !!formError && formError.code !== 'REQUIRES_RISK_ACKNOWLEDGEMENT' && + formError.code !== 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' && formError.code !== 'MISSING_DATA' } /> @@ -427,10 +456,21 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => balanceMutations={balanceMutations} /> - {shouldAskUserRiskAcknowledgement && ( - handleToggleAcknowledgeRisk(checked)} + label={t('operationForm.acknowledgements.riskyOperation.label')} + tooltip={t('operationForm.acknowledgements.riskyOperation.tooltip')} + /> + )} + + {shouldAskPriceImpactAcknowledgement && ( + handleToggleAcknowledgeHighPriceImpact(checked)} + label={t('operationForm.acknowledgements.highPriceImpact.label')} + tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip')} /> )} @@ -439,7 +479,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx index 05f9920d77..fe4616896b 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx @@ -25,7 +25,7 @@ export interface UseFormInput { interface UseFormOutput { handleSubmit: (e?: React.SyntheticEvent) => Promise; isFormValid: boolean; - formError?: FormError; + formErrors: FormError[]; } const useForm = ({ @@ -41,7 +41,7 @@ const useForm = ({ getSwapQuoteError, onSubmit, }: UseFormInput): UseFormOutput => { - const { isFormValid, formError } = useFormValidation({ + const { isFormValid, formErrors } = useFormValidation({ asset: borrowedAsset, pool, limitTokens, @@ -75,7 +75,7 @@ const useForm = ({ return { handleSubmit, isFormValid, - formError, + formErrors, }; }; diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/types.ts b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/types.ts index 9ac5a0f02d..530cf22901 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/types.ts +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/types.ts @@ -4,6 +4,7 @@ export interface FormValues { suppliedToken: Token; amountTokens: string; acknowledgeRisk: boolean; + acknowledgeHighPriceImpact: boolean; } export type FormErrorCode = @@ -16,6 +17,7 @@ export type FormErrorCode = | 'HIGHER_THAN_AVAILABLE_AMOUNT' | 'TOO_RISKY' | 'REQUIRES_RISK_ACKNOWLEDGEMENT' + | 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' | 'NO_SWAP_QUOTE_FOUND' | 'MISSING_DATA' | 'SWAP_PRICE_IMPACT_TOO_HIGH'; diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts index 333bf238bc..36743ae0b8 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts @@ -5,7 +5,10 @@ import { HEALTH_FACTOR_LIQUIDATION_THRESHOLD, HEALTH_FACTOR_MODERATE_THRESHOLD, } from 'constants/healthFactor'; -import { MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE } from 'constants/swap'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import type { VError } from 'libs/errors'; import { useTranslation } from 'libs/translations'; import type { Asset, Pool, SwapQuote } from 'types'; @@ -26,7 +29,7 @@ interface UseFormValidationInput { interface UseFormValidationOutput { isFormValid: boolean; - formError?: FormError; + formErrors: FormError[]; } const useFormValidation = ({ @@ -41,21 +44,23 @@ const useFormValidation = ({ }: UseFormValidationInput): UseFormValidationOutput => { const { t } = useTranslation(); - const formError = useMemo | undefined>(() => { + const formErrors = useMemo[]>(() => { + const tmpErrors: FormError[] = []; + if (!pool?.userBorrowLimitCents || pool.userBorrowLimitCents.isEqualTo(0)) { - return { + tmpErrors.push({ code: 'NO_COLLATERALS', message: t('operationForm.error.noCollateral', { tokenSymbol: asset.vToken.underlyingToken.symbol, }), - }; + }); } if ( asset.borrowCapTokens && asset.borrowBalanceTokens.isGreaterThanOrEqualTo(asset.borrowCapTokens) ) { - return { + tmpErrors.push({ code: 'BORROW_CAP_ALREADY_REACHED', message: t('operationForm.error.borrowCapReached', { assetBorrowCap: formatTokensToReadableValue({ @@ -63,14 +68,14 @@ const useFormValidation = ({ token: asset.vToken.underlyingToken, }), }), - }; + }); } if (getSwapQuoteError?.code === 'noSwapQuoteFound') { - return { + tmpErrors.push({ code: 'NO_SWAP_QUOTE_FOUND', message: t('operationForm.error.noSwapQuoteFound'), - }; + }); } const borrowedTokenAmountTokens = formValues.amountTokens @@ -78,15 +83,16 @@ const useFormValidation = ({ : undefined; if (!borrowedTokenAmountTokens || borrowedTokenAmountTokens.isLessThanOrEqualTo(0)) { - return { + tmpErrors.push({ code: 'EMPTY_TOKEN_AMOUNT', - }; + }); } if ( + borrowedTokenAmountTokens && asset.borrowBalanceTokens.plus(borrowedTokenAmountTokens).isGreaterThan(asset.borrowCapTokens) ) { - return { + tmpErrors.push({ code: 'HIGHER_THAN_BORROW_CAP', message: t('operationForm.error.higherThanBorrowCap', { userMaxBorrowAmount: formatTokensToReadableValue({ @@ -105,7 +111,7 @@ const useFormValidation = ({ maxDecimalPlaces: asset.vToken.underlyingToken.decimals, }), }), - }; + }); } if ( @@ -114,7 +120,7 @@ const useFormValidation = ({ .plus(expectedSuppliedAmountTokens) .isGreaterThan(asset.supplyCapTokens) ) { - return { + tmpErrors.push({ code: 'HIGHER_THAN_SUPPLY_CAP', message: t('operationForm.error.higherThanSupplyCap', { userMaxSupplyAmount: formatTokensToReadableValue({ @@ -133,46 +139,57 @@ const useFormValidation = ({ maxDecimalPlaces: asset.vToken.underlyingToken.decimals, }), }), - }; + }); } const assetLiquidityTokens = new BigNumber(asset.liquidityCents).dividedBy( asset.tokenPriceCents, ); - if (borrowedTokenAmountTokens.isGreaterThan(assetLiquidityTokens)) { + if (borrowedTokenAmountTokens?.isGreaterThan(assetLiquidityTokens)) { // User is trying to borrow more than available liquidity - return { + tmpErrors.push({ code: 'HIGHER_THAN_LIQUIDITY', message: t('operationForm.error.higherThanAvailableLiquidity'), - }; + }); } - if (borrowedTokenAmountTokens.isGreaterThan(limitTokens)) { - return { + if (borrowedTokenAmountTokens?.isGreaterThan(limitTokens)) { + tmpErrors.push({ code: 'HIGHER_THAN_AVAILABLE_AMOUNT', message: t('operationForm.error.higherThanAvailableAmount'), - }; + }); } if ( simulatedPool?.userHealthFactor !== undefined && simulatedPool.userHealthFactor <= HEALTH_FACTOR_LIQUIDATION_THRESHOLD ) { - return { + tmpErrors.push({ code: 'TOO_RISKY', message: t('operationForm.error.tooRisky'), - }; + }); } if ( swapQuote && swapQuote?.priceImpactPercentage >= MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE ) { - return { + tmpErrors.push({ code: 'SWAP_PRICE_IMPACT_TOO_HIGH', message: t('operationForm.error.priceImpactTooHigh'), - }; + }); + } + + if ( + swapQuote && + swapQuote?.priceImpactPercentage >= HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + swapQuote?.priceImpactPercentage < MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + !formValues.acknowledgeHighPriceImpact + ) { + tmpErrors.push({ + code: 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT', + }); } if ( @@ -180,16 +197,18 @@ const useFormValidation = ({ simulatedPool.userHealthFactor < HEALTH_FACTOR_MODERATE_THRESHOLD && !formValues.acknowledgeRisk ) { - return { + tmpErrors.push({ code: 'REQUIRES_RISK_ACKNOWLEDGEMENT', - }; + }); } if (!simulatedPool || !expectedSuppliedAmountTokens) { - return { + tmpErrors.push({ code: 'MISSING_DATA', - }; + }); } + + return tmpErrors; }, [ asset, pool, @@ -199,13 +218,14 @@ const useFormValidation = ({ expectedSuppliedAmountTokens, getSwapQuoteError, formValues.acknowledgeRisk, + formValues.acknowledgeHighPriceImpact, swapQuote, t, ]); return { - isFormValid: !formError, - formError, + isFormValid: !formErrors.length, + formErrors, }; }; diff --git a/apps/evm/src/pages/Market/OperationForm/BorrowForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/BorrowForm/__tests__/index.spec.tsx index f004ab4900..bca90f80a7 100644 --- a/apps/evm/src/pages/Market/OperationForm/BorrowForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BorrowForm/__tests__/index.spec.tsx @@ -363,7 +363,7 @@ describe('BorrowForm', () => { await waitFor(() => expect(tokenTextInput.value).toBe(marginWithRiskyThresholdTokens)); // Check warning is displayed - expect(getByText(en.operationForm.riskyOperation.warning)); + expect(getByText(en.operationForm.acknowledgements.riskyOperation.tooltip)); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; diff --git a/apps/evm/src/pages/Market/OperationForm/BorrowForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BorrowForm/index.tsx index 497c0c4f88..2aa478b0c6 100644 --- a/apps/evm/src/pages/Market/OperationForm/BorrowForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BorrowForm/index.tsx @@ -4,9 +4,9 @@ import { useEffect, useMemo, useState } from 'react'; import { cn } from '@venusprotocol/ui'; import { useBorrow } from 'clients/api'; import { + AcknowledgementToggle, Delimiter, LabeledInlineContent, - RiskAcknowledgementToggle, Toggle, TokenTextField, } from 'components'; @@ -364,7 +364,9 @@ export const BorrowFormUi: React.FC = ({ /> {shouldAskUserRiskAcknowledgement && ( - handleToggleAcknowledgeRisk(checked)} /> diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx index 1211869a34..6a3ffeb7ae 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx @@ -443,7 +443,7 @@ describe('RepayWithCollateralForm', () => { }); // Check warning is displayed - expect(getByText(en.operationForm.riskyOperation.warning)); + expect(getByText(en.operationForm.acknowledgements.riskyOperation.tooltip)); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx index fa305a40dd..84bbc0d5db 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx @@ -9,10 +9,10 @@ import { useRepayWithCollateral, } from 'clients/api'; import { + AcknowledgementToggle, Icon, LabeledInlineContent, type OptionalTokenBalance, - RiskAcknowledgementToggle, SelectTokenTextField, TokenTextField, } from 'components'; @@ -455,7 +455,9 @@ export const RepayWithCollateralForm: React.FC = ( /> {shouldAskUserRiskAcknowledgement && ( - handleToggleAcknowledgeRisk(checked)} /> diff --git a/apps/evm/src/pages/Market/OperationForm/WithdrawForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/WithdrawForm/__tests__/index.spec.tsx index c46fc82e38..df7bd8cbd8 100644 --- a/apps/evm/src/pages/Market/OperationForm/WithdrawForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/WithdrawForm/__tests__/index.spec.tsx @@ -341,7 +341,7 @@ describe('WithdrawForm', () => { await waitFor(() => expect(tokenTextInput.value).toBe(inputValue)); // Check warning is displayed - expect(getByText(en.operationForm.riskyOperation.warning)); + expect(getByText(en.operationForm.acknowledgements.riskyOperation.tooltip)); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; diff --git a/apps/evm/src/pages/Market/OperationForm/WithdrawForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/WithdrawForm/index.tsx index 5627d48d44..89592840b8 100644 --- a/apps/evm/src/pages/Market/OperationForm/WithdrawForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/WithdrawForm/index.tsx @@ -4,9 +4,9 @@ import { useEffect, useMemo, useState } from 'react'; import { cn } from '@venusprotocol/ui'; import { useGetVTokenBalance, useWithdraw } from 'clients/api'; import { + AcknowledgementToggle, Delimiter, LabeledInlineContent, - RiskAcknowledgementToggle, Toggle, TokenTextField, } from 'components'; @@ -377,7 +377,9 @@ export const WithdrawFormUi: React.FC = ({ /> {shouldAskUserRiskAcknowledgement && ( - handleToggleAcknowledgeRisk(checked)} /> diff --git a/apps/evm/src/pages/Vai/Borrow/index.tsx b/apps/evm/src/pages/Vai/Borrow/index.tsx index 0667c12bee..9e0fea125f 100644 --- a/apps/evm/src/pages/Vai/Borrow/index.tsx +++ b/apps/evm/src/pages/Vai/Borrow/index.tsx @@ -10,11 +10,11 @@ import { useMintVai, } from 'clients/api'; import { + AcknowledgementToggle, Delimiter, LabeledInlineContent, NoticeError, NoticeWarning, - RiskAcknowledgementToggle, Spinner, } from 'components'; import PLACEHOLDER_KEY from 'constants/placeholderKey'; @@ -320,7 +320,13 @@ export const Borrow: React.FC = () => { } + render={({ field }) => ( + + )} /> )} From 3f515cb054172c351366095f18e78c3e5e3e0f92 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Wed, 31 Dec 2025 15:40:03 +0800 Subject: [PATCH 05/12] feat(evm): add high price impact warning for repayWithCollateral, update warning text --- .../libs/translations/translations/en.json | 4 +- .../Market/OperationForm/BoostForm/index.tsx | 5 +- .../SubmitSection/index.tsx | 6 +- .../__tests__/index.spec.tsx | 55 ++++++++++++++++- .../Repay/RepayWithCollateralForm/index.tsx | 53 ++++++++++++++-- .../RepayWithCollateralForm/useForm/index.tsx | 6 +- .../RepayWithCollateralForm/useForm/types.ts | 2 + .../useForm/useFormValidation.ts | 61 ++++++++++++------- 8 files changed, 158 insertions(+), 34 deletions(-) diff --git a/apps/evm/src/libs/translations/translations/en.json b/apps/evm/src/libs/translations/translations/en.json index c1102657a0..a28a486f64 100644 --- a/apps/evm/src/libs/translations/translations/en.json +++ b/apps/evm/src/libs/translations/translations/en.json @@ -765,8 +765,8 @@ }, "acknowledgements": { "highPriceImpact": { - "label": "I acknowledge the risks involved", - "tooltip": "This swap is unfavorable" + "label": "I acknowledge the erosion involved", + "tooltip": "This transaction is expected to result in a value erosion of over {{priceImpactPercentage}}%." }, "riskyOperation": { "label": "I acknowledge the risks involved", diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx index 3538b17d34..43f1e84fff 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx @@ -470,7 +470,10 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => value={formValues.acknowledgeHighPriceImpact} onChange={(_, checked) => handleToggleAcknowledgeHighPriceImpact(checked)} label={t('operationForm.acknowledgements.highPriceImpact.label')} - tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip')} + tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip', { + priceImpactPercentage: + swapQuote?.priceImpactPercentage ?? HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + })} /> )} diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx index 96b5daaebd..7162d59f69 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx @@ -43,7 +43,11 @@ export const SubmitSection: React.FC = ({ const approveDelegate = () => updatePoolDelegateStatus({ approvedStatus: true }); const submitButtonLabel = useMemo(() => { - if (!isFormValid && formErrorCode !== 'REQUIRES_RISK_ACKNOWLEDGEMENT') { + if ( + !isFormValid && + formErrorCode !== 'REQUIRES_RISK_ACKNOWLEDGEMENT' && + formErrorCode !== 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' + ) { return t('operationForm.submitButtonLabel.enterValidAmount'); } diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx index 6a3ffeb7ae..95fb078368 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx @@ -18,7 +18,10 @@ import { HEALTH_FACTOR_LIQUIDATION_THRESHOLD, HEALTH_FACTOR_MODERATE_THRESHOLD, } from 'constants/healthFactor'; -import { MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE } from 'constants/swap'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import { useSimulateBalanceMutations } from 'hooks/useSimulateBalanceMutations'; import { VError } from 'libs/errors'; import { en } from 'libs/translations'; @@ -413,6 +416,56 @@ describe('RepayWithCollateralForm', () => { await checkSubmitButtonIsDisabled(); }); + it('prompts user to acknowledge high price impact', async () => { + const customFakeSwapQuote: SwapQuote = { + ...fakeExactInSwapQuote, + priceImpactPercentage: HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + }; + + (useGetSwapQuote as Mock).mockImplementation(() => ({ + isLoading: false, + data: { + swapQuote: customFakeSwapQuote, + }, + })); + + const { getByTestId, getByText, getByRole } = renderComponent( + , + { + accountAddress: fakeAccountAddress, + }, + ); + + const selectTokenTextField = getByTestId( + getTokenTextFieldTestId({ + parentTestId: TEST_IDS.selectCollateralTokenTextField, + }), + ) as HTMLInputElement; + + // Enter amount in input + fireEvent.change(selectTokenTextField, { + target: { value: 10 }, + }); + + // Check warning is displayed + expect(getByText(en.operationForm.acknowledgements.highPriceImpact.tooltip)); + + // Check submit button is disabled + const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; + await waitFor(() => + expect(submitButton).toHaveTextContent(en.operationForm.submitButtonLabel.repay), + ); + expect(submitButton).toBeDisabled(); + + // Toggle acknowledgement + const toggle = getByRole('checkbox'); + fireEvent.click(toggle); + + await checkSubmitButtonIsEnabled({ + textContent: en.operationForm.submitButtonLabel.repay, + }); + }); + it('prompts user to acknowledge risk if position would lower health factor to risky threshold', async () => { (useSimulateBalanceMutations as Mock).mockImplementation(() => ({ isLoading: false, diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx index 84bbc0d5db..6b02abe45d 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx @@ -18,6 +18,10 @@ import { } from 'components'; import { NULL_ADDRESS } from 'constants/address'; import { HEALTH_FACTOR_MODERATE_THRESHOLD } from 'constants/healthFactor'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import { ConnectWallet } from 'containers/ConnectWallet'; import { SwapDetails } from 'containers/SwapDetails'; import useDebounceValue from 'hooks/useDebounceValue'; @@ -25,6 +29,7 @@ import { useGetContractAddress } from 'hooks/useGetContractAddress'; import { useGetUserSlippageTolerance } from 'hooks/useGetUserSlippageTolerance'; import { useSimulateBalanceMutations } from 'hooks/useSimulateBalanceMutations'; import { VError } from 'libs/errors'; + import { useTranslation } from 'libs/translations'; import { useAccountAddress } from 'libs/wallet'; import type { Asset, BalanceMutation, Pool } from 'types'; @@ -38,10 +43,11 @@ import { } from 'utilities'; import { ApyBreakdown } from '../../ApyBreakdown'; import { OperationDetails } from '../../OperationDetails'; +import type { FormError } from '../../types'; import { Notice } from '../Notice'; import { SubmitSection } from './SubmitSection'; import TEST_IDS from './testIds'; -import useForm, { type FormValues, type UseFormInput } from './useForm'; +import useForm, { type FormErrorCode, type FormValues, type UseFormInput } from './useForm'; export interface RepayWithCollateralFormProps { asset: Asset; @@ -83,6 +89,7 @@ export const RepayWithCollateralForm: React.FC = ( collateralAmountTokens: '', repaidAmountTokens: '', acknowledgeRisk: false, + acknowledgeHighPriceImpact: false, repayFullLoan: false, }; @@ -263,7 +270,12 @@ export const RepayWithCollateralForm: React.FC = ( simulatedPool?.userHealthFactor !== undefined && simulatedPool?.userHealthFactor < HEALTH_FACTOR_MODERATE_THRESHOLD; - const { handleSubmit, isFormValid, formError } = useForm({ + const isHighPriceImpact = + swapQuote?.priceImpactPercentage !== undefined && + swapQuote?.priceImpactPercentage >= HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + swapQuote?.priceImpactPercentage < MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE; + + const { handleSubmit, isFormValid, formErrors } = useForm({ limitTokens, repaidAsset, simulatedPool, @@ -276,6 +288,8 @@ export const RepayWithCollateralForm: React.FC = ( getSwapQuoteError: getSwapQuoteError || undefined, }); + const formError: FormError | undefined = formErrors[0]; + const handleToggleAcknowledgeRisk = (checked: boolean) => { setFormValues(currentFormValues => ({ ...currentFormValues, @@ -283,6 +297,13 @@ export const RepayWithCollateralForm: React.FC = ( })); }; + const handleToggleAcknowledgeHighPriceImpact = (checked: boolean) => { + setFormValues(currentFormValues => ({ + ...currentFormValues, + acknowledgeHighPriceImpact: checked, + })); + }; + const handleMaxCollateralButtonClick = () => { setFormValues(currentFormValues => ({ ...currentFormValues, @@ -306,8 +327,17 @@ export const RepayWithCollateralForm: React.FC = ( })); }; - const shouldAskUserRiskAcknowledgement = - isRiskyOperation && (!formError || formError?.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT'); + const shouldAskRiskAcknowledgement = + isRiskyOperation && + (!formError || + formError.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT' || + formError.code === 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT'); + + const shouldAskPriceImpactAcknowledgement = + isHighPriceImpact && + (!formError || + formError.code === 'REQUIRES_RISK_ACKNOWLEDGEMENT' || + formError.code === 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT'); const isDisabled = !accountAddress || isSubmitting; @@ -326,6 +356,7 @@ export const RepayWithCollateralForm: React.FC = ( !isSubmitting && !!formError && formError.code !== 'REQUIRES_RISK_ACKNOWLEDGEMENT' && + formError.code !== 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' && formError.code !== 'MISSING_DATA' && formError.code !== 'EMPTY_TOKEN_AMOUNT' && formError.code !== 'HIGHER_THAN_BORROW_BALANCE' @@ -454,7 +485,7 @@ export const RepayWithCollateralForm: React.FC = ( showApyBreakdown={false} /> - {shouldAskUserRiskAcknowledgement && ( + {shouldAskRiskAcknowledgement && ( = ( onChange={(_, checked) => handleToggleAcknowledgeRisk(checked)} /> )} + + {shouldAskPriceImpactAcknowledgement && ( + handleToggleAcknowledgeHighPriceImpact(checked)} + label={t('operationForm.acknowledgements.highPriceImpact.label')} + tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip', { + priceImpactPercentage: + swapQuote?.priceImpactPercentage ?? HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + })} + /> + )}
diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/index.tsx index e04bc97af6..992a94fca7 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/index.tsx @@ -27,7 +27,7 @@ export interface UseFormInput { interface UseFormOutput { handleSubmit: (e?: React.SyntheticEvent) => Promise; isFormValid: boolean; - formError?: FormError; + formErrors: FormError[]; } const useForm = ({ @@ -42,7 +42,7 @@ const useForm = ({ getSwapQuoteError, isUsingSwap, }: UseFormInput): UseFormOutput => { - const { isFormValid, formError } = useFormValidation({ + const { isFormValid, formErrors } = useFormValidation({ limitTokens, formValues, simulatedPool, @@ -115,7 +115,7 @@ const useForm = ({ return { handleSubmit, isFormValid, - formError, + formErrors, }; }; diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/types.ts b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/types.ts index c9fdbaa27c..de03909d97 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/types.ts +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/types.ts @@ -6,6 +6,7 @@ export interface FormValues { collateralAmountTokens: string; repaidAmountTokens: string; acknowledgeRisk: boolean; + acknowledgeHighPriceImpact: boolean; repayFullLoan: boolean; } @@ -15,6 +16,7 @@ export type FormErrorCode = | 'HIGHER_THAN_AVAILABLE_AMOUNT' | 'TOO_RISKY' | 'REQUIRES_RISK_ACKNOWLEDGEMENT' + | 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT' | 'NO_SWAP_QUOTE_FOUND' | 'MISSING_DATA' | 'SWAP_PRICE_IMPACT_TOO_HIGH'; diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts index 861fa02a80..c89b7241c6 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts @@ -5,7 +5,10 @@ import { HEALTH_FACTOR_LIQUIDATION_THRESHOLD, HEALTH_FACTOR_MODERATE_THRESHOLD, } from 'constants/healthFactor'; -import { MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE } from 'constants/swap'; +import { + HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, +} from 'constants/swap'; import type { VError } from 'libs/errors'; import { useTranslation } from 'libs/translations'; import type { Asset, Pool, SwapQuote } from 'types'; @@ -24,7 +27,7 @@ interface UseFormValidationInput { interface UseFormValidationOutput { isFormValid: boolean; - formError?: FormError; + formErrors: FormError[]; } const useFormValidation = ({ @@ -38,7 +41,9 @@ const useFormValidation = ({ }: UseFormValidationInput): UseFormValidationOutput => { const { t } = useTranslation(); - const formError = useMemo | undefined>(() => { + const formErrors = useMemo[]>(() => { + const tmpErrors: FormError[] = []; + const collateralAmountTokens = formValues.collateralAmountTokens ? new BigNumber(formValues.collateralAmountTokens) : undefined; @@ -48,50 +53,61 @@ const useFormValidation = ({ : undefined; if (collateralAmountTokens?.isGreaterThan(limitTokens)) { - return { + tmpErrors.push({ code: 'HIGHER_THAN_AVAILABLE_AMOUNT', message: t('operationForm.error.higherThanAvailableAmount'), - }; + }); } if (repaidAmountTokens?.isGreaterThan(repaidAsset.userBorrowBalanceTokens)) { - return { + tmpErrors.push({ code: 'HIGHER_THAN_BORROW_BALANCE', message: t('operationForm.error.higherThanBorrowBalance'), - }; + }); } if (getSwapQuoteError?.code === 'noSwapQuoteFound') { - return { + tmpErrors.push({ code: 'NO_SWAP_QUOTE_FOUND', message: t('operationForm.error.noSwapQuoteFound'), - }; + }); } if (!collateralAmountTokens?.isGreaterThan(0) || !repaidAmountTokens?.isGreaterThan(0)) { - return { + tmpErrors.push({ code: 'EMPTY_TOKEN_AMOUNT', - }; + }); } if ( swapQuote && swapQuote?.priceImpactPercentage >= MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE ) { - return { + tmpErrors.push({ code: 'SWAP_PRICE_IMPACT_TOO_HIGH', message: t('operationForm.error.priceImpactTooHigh'), - }; + }); + } + + if ( + swapQuote && + swapQuote?.priceImpactPercentage >= HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + swapQuote?.priceImpactPercentage < MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE && + !formValues.acknowledgeHighPriceImpact + ) { + tmpErrors.push({ + code: 'REQUIRES_SWAP_PRICE_IMPACT_ACKNOWLEDGEMENT', + }); } if ( simulatedPool?.userHealthFactor !== undefined && simulatedPool.userHealthFactor <= HEALTH_FACTOR_LIQUIDATION_THRESHOLD ) { - return { + tmpErrors.push({ code: 'TOO_RISKY', message: t('operationForm.error.tooRisky'), - }; + }); } if ( @@ -99,20 +115,23 @@ const useFormValidation = ({ simulatedPool.userHealthFactor < HEALTH_FACTOR_MODERATE_THRESHOLD && !formValues.acknowledgeRisk ) { - return { + tmpErrors.push({ code: 'REQUIRES_RISK_ACKNOWLEDGEMENT', - }; + }); } if (!simulatedPool || (!swapQuote && isUsingSwap)) { - return { + tmpErrors.push({ code: 'MISSING_DATA', - }; + }); } + + return tmpErrors; }, [ limitTokens, formValues.collateralAmountTokens, formValues.acknowledgeRisk, + formValues.acknowledgeHighPriceImpact, formValues.repaidAmountTokens, repaidAsset.userBorrowBalanceTokens, t, @@ -123,8 +142,8 @@ const useFormValidation = ({ ]); return { - isFormValid: !formError, - formError, + isFormValid: !formErrors.length, + formErrors, }; }; From 71ea2884acd038c1846c8ee9fd0a305bb969122d Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Wed, 31 Dec 2025 19:06:33 +0800 Subject: [PATCH 06/12] feat(evm): add price displaying in ValueUpdate --- .../src/components/BalanceUpdates/index.tsx | 50 ++++++++++++++----- apps/evm/src/components/ValueUpdate/index.tsx | 10 +++- apps/evm/src/pages/Bridge/index.tsx | 2 +- .../BoostForm/__tests__/index.spec.tsx | 9 +++- .../__tests__/index.spec.tsx | 9 +++- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/apps/evm/src/components/BalanceUpdates/index.tsx b/apps/evm/src/components/BalanceUpdates/index.tsx index f6fdeb10d1..f7c79b6900 100644 --- a/apps/evm/src/components/BalanceUpdates/index.tsx +++ b/apps/evm/src/components/BalanceUpdates/index.tsx @@ -1,7 +1,12 @@ +import BigNumber from 'bignumber.js'; import { LabeledInlineContent, type LabeledInlineContentProps, ValueUpdate } from 'components'; import { useTranslation } from 'libs/translations'; import type { BalanceMutation, Pool } from 'types'; -import { areAddressesEqual, formatTokensToReadableValue } from 'utilities'; +import { + areAddressesEqual, + formatCentsToReadableValue, + formatTokensToReadableValue, +} from 'utilities'; export interface BalanceUpdatesProps { pool: Pool; @@ -53,24 +58,43 @@ export const BalanceUpdates: React.FC = ({ simulatedBalanceTokens = simulatedAsset?.userSupplyBalanceTokens; } + const original = formatTokensToReadableValue({ + token: asset.vToken.underlyingToken, + value: balanceTokens, + addSymbol: false, + }); + + const update = + simulatedBalanceTokens && + formatTokensToReadableValue({ + token: asset.vToken.underlyingToken, + value: simulatedBalanceTokens, + addSymbol: false, + }); + + const tokenValue = formatCentsToReadableValue({ + value: + simulatedBalanceTokens && asset.tokenPriceCents + ? asset.tokenPriceCents.times(new BigNumber(simulatedBalanceTokens)) + : undefined, + }); + const row: LabeledInlineContentProps = { iconSrc: asset.vToken.underlyingToken, label, children: ( + {update} + {tokenValue ? ` (+${tokenValue})` : ''} +
+ ) : undefined } + className="items-start" + iconClassName="translate-y-0.5" /> ), }; @@ -81,7 +105,7 @@ export const BalanceUpdates: React.FC = ({ return (
{balanceUpdateRows.map(row => ( - + ))}
); diff --git a/apps/evm/src/components/ValueUpdate/index.tsx b/apps/evm/src/components/ValueUpdate/index.tsx index fac7e27d48..26d2a6815a 100644 --- a/apps/evm/src/components/ValueUpdate/index.tsx +++ b/apps/evm/src/components/ValueUpdate/index.tsx @@ -4,15 +4,21 @@ import { Icon } from '../Icon'; export interface ValueUpdateProps extends React.HTMLAttributes { original: React.ReactNode; update?: React.ReactNode; + iconClassName?: string; } -export const ValueUpdate: React.FC = ({ className, original, update }) => ( +export const ValueUpdate: React.FC = ({ + className, + original, + update, + iconClassName, +}) => (
{original} {update && ( <> - + {update} diff --git a/apps/evm/src/pages/Bridge/index.tsx b/apps/evm/src/pages/Bridge/index.tsx index 7c938704a9..f36db5df03 100644 --- a/apps/evm/src/pages/Bridge/index.tsx +++ b/apps/evm/src/pages/Bridge/index.tsx @@ -291,7 +291,7 @@ const BridgePage: React.FC = () => {
-
+
{ await waitFor(() => expect(tokenTextInput.value).toEqual('10')); // Check warning is displayed - expect(getByText(en.operationForm.acknowledgements.highPriceImpact.tooltip)); + expect( + getByText( + en.operationForm.acknowledgements.highPriceImpact.tooltip.replace( + '{{priceImpactPercentage}}', + `${HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE}`, + ), + ), + ); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx index 95fb078368..f87bda89b8 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/__tests__/index.spec.tsx @@ -448,7 +448,14 @@ describe('RepayWithCollateralForm', () => { }); // Check warning is displayed - expect(getByText(en.operationForm.acknowledgements.highPriceImpact.tooltip)); + expect( + getByText( + en.operationForm.acknowledgements.highPriceImpact.tooltip.replace( + '{{priceImpactPercentage}}', + `${HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE}`, + ), + ), + ); // Check submit button is disabled const submitButton = document.querySelector('button[type="submit"]') as HTMLButtonElement; From 04c44666b906f7e320132ae1f6a365fe829a251b Mon Sep 17 00:00:00 2001 From: therealemjy Date: Wed, 31 Dec 2025 13:54:15 +0100 Subject: [PATCH 07/12] refactor: design + logic updates --- .changeset/kind-areas-rescue.md | 5 ++ .../src/components/BalanceUpdates/index.tsx | 67 ++++++++++--------- apps/evm/src/components/ValueUpdate/index.tsx | 10 +-- .../libs/translations/translations/en.json | 4 +- .../Market/OperationForm/BoostForm/index.tsx | 3 +- .../SubmitSection/index.tsx | 5 +- .../Repay/RepayWithCollateralForm/index.tsx | 4 +- .../useForm/useFormValidation.ts | 20 +++--- 8 files changed, 63 insertions(+), 55 deletions(-) create mode 100644 .changeset/kind-areas-rescue.md diff --git a/.changeset/kind-areas-rescue.md b/.changeset/kind-areas-rescue.md new file mode 100644 index 0000000000..aaf2e131e3 --- /dev/null +++ b/.changeset/kind-areas-rescue.md @@ -0,0 +1,5 @@ +--- +"@venusprotocol/evm": minor +--- + +improve hgih price impact handling + display USD values of balance updates diff --git a/apps/evm/src/components/BalanceUpdates/index.tsx b/apps/evm/src/components/BalanceUpdates/index.tsx index f7c79b6900..38155b8686 100644 --- a/apps/evm/src/components/BalanceUpdates/index.tsx +++ b/apps/evm/src/components/BalanceUpdates/index.tsx @@ -1,4 +1,4 @@ -import BigNumber from 'bignumber.js'; +import type BigNumber from 'bignumber.js'; import { LabeledInlineContent, type LabeledInlineContentProps, ValueUpdate } from 'components'; import { useTranslation } from 'libs/translations'; import type { BalanceMutation, Pool } from 'types'; @@ -8,6 +8,11 @@ import { formatTokensToReadableValue, } from 'utilities'; +interface Row { + labeledInlineContentProps: LabeledInlineContentProps; + readableAmountDollars?: string; +} + export interface BalanceUpdatesProps { pool: Pool; simulatedPool?: Pool; @@ -21,9 +26,7 @@ export const BalanceUpdates: React.FC = ({ }) => { const { t } = useTranslation(); - const balanceUpdateRows: LabeledInlineContentProps[] = balanceMutations.reduce< - LabeledInlineContentProps[] - >((acc, balanceMutation) => { + const balanceUpdateRows: Row[] = balanceMutations.reduce((acc, balanceMutation) => { // Skip VAI updates if (balanceMutation.type === 'vai') { return acc; @@ -72,31 +75,28 @@ export const BalanceUpdates: React.FC = ({ addSymbol: false, }); - const tokenValue = formatCentsToReadableValue({ - value: - simulatedBalanceTokens && asset.tokenPriceCents - ? asset.tokenPriceCents.times(new BigNumber(simulatedBalanceTokens)) - : undefined, - }); + const updateAmountTokens = simulatedBalanceTokens + ? simulatedBalanceTokens.minus(balanceTokens) + : undefined; + + let readableAmountDollars = updateAmountTokens + ? formatCentsToReadableValue({ + value: asset.tokenPriceCents.times(updateAmountTokens).absoluteValue(), + }) + : undefined; + + if (readableAmountDollars && updateAmountTokens) { + const sign = updateAmountTokens.isLessThan(0) ? '-' : '+'; + readableAmountDollars = `${sign} ${readableAmountDollars}`; + } - const row: LabeledInlineContentProps = { - iconSrc: asset.vToken.underlyingToken, - label, - children: ( - - {update} - {tokenValue ? ` (+${tokenValue})` : ''} -
- ) : undefined - } - className="items-start" - iconClassName="translate-y-0.5" - /> - ), + const row: Row = { + readableAmountDollars, + labeledInlineContentProps: { + iconSrc: asset.vToken.underlyingToken, + label, + children: , + }, }; return [...acc, row]; @@ -104,8 +104,15 @@ export const BalanceUpdates: React.FC = ({ return (
- {balanceUpdateRows.map(row => ( - + {balanceUpdateRows.map(({ labeledInlineContentProps, readableAmountDollars }) => ( +
+ + + {readableAmountDollars &&

{readableAmountDollars}

} +
))}
); diff --git a/apps/evm/src/components/ValueUpdate/index.tsx b/apps/evm/src/components/ValueUpdate/index.tsx index 26d2a6815a..01a83170f0 100644 --- a/apps/evm/src/components/ValueUpdate/index.tsx +++ b/apps/evm/src/components/ValueUpdate/index.tsx @@ -4,21 +4,15 @@ import { Icon } from '../Icon'; export interface ValueUpdateProps extends React.HTMLAttributes { original: React.ReactNode; update?: React.ReactNode; - iconClassName?: string; } -export const ValueUpdate: React.FC = ({ - className, - original, - update, - iconClassName, -}) => ( +export const ValueUpdate: React.FC = ({ className, original, update }) => (
{original} {update && ( <> - + {update} diff --git a/apps/evm/src/libs/translations/translations/en.json b/apps/evm/src/libs/translations/translations/en.json index a28a486f64..1fb2f01b86 100644 --- a/apps/evm/src/libs/translations/translations/en.json +++ b/apps/evm/src/libs/translations/translations/en.json @@ -765,8 +765,8 @@ }, "acknowledgements": { "highPriceImpact": { - "label": "I acknowledge the erosion involved", - "tooltip": "This transaction is expected to result in a value erosion of over {{priceImpactPercentage}}%." + "label": "I acknowledge the high price impact", + "tooltip": "This transaction is expected to have a price impact of over {{priceImpactPercentage}}%" }, "riskyOperation": { "label": "I acknowledge the risks involved", diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx index 43f1e84fff..7fcf848ee7 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx @@ -471,8 +471,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => onChange={(_, checked) => handleToggleAcknowledgeHighPriceImpact(checked)} label={t('operationForm.acknowledgements.highPriceImpact.label')} tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip', { - priceImpactPercentage: - swapQuote?.priceImpactPercentage ?? HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + priceImpactPercentage: HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, })} /> )} diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx index 7162d59f69..329de0e569 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/SubmitSection/index.tsx @@ -1,3 +1,4 @@ +import { cn } from '@venusprotocol/ui'; import { useMemo } from 'react'; import { PrimaryButton } from 'components'; @@ -15,6 +16,7 @@ export interface SubmitSectionProps { isLoading: boolean; poolComptrollerContractAddress: Address; formErrorCode?: FormErrorCode; + isRiskyOperation: boolean; } export const SubmitSection: React.FC = ({ @@ -22,6 +24,7 @@ export const SubmitSection: React.FC = ({ isLoading, formErrorCode, poolComptrollerContractAddress, + isRiskyOperation, }) => { const { t } = useTranslation(); @@ -59,7 +62,7 @@ export const SubmitSection: React.FC = ({ type="submit" loading={isLoading} disabled={!isFormValid || isLoading} - className="w-full" + className={cn('w-full', isRiskyOperation && 'border-red bg-red')} > {submitButtonLabel} diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx index 6b02abe45d..7a4f57726f 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx @@ -500,8 +500,7 @@ export const RepayWithCollateralForm: React.FC = ( onChange={(_, checked) => handleToggleAcknowledgeHighPriceImpact(checked)} label={t('operationForm.acknowledgements.highPriceImpact.label')} tooltip={t('operationForm.acknowledgements.highPriceImpact.tooltip', { - priceImpactPercentage: - swapQuote?.priceImpactPercentage ?? HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, + priceImpactPercentage: HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, })} /> )} @@ -511,6 +510,7 @@ export const RepayWithCollateralForm: React.FC = ( diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts index c89b7241c6..b1c057d036 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts @@ -79,6 +79,16 @@ const useFormValidation = ({ }); } + if ( + simulatedPool?.userHealthFactor !== undefined && + simulatedPool.userHealthFactor <= HEALTH_FACTOR_LIQUIDATION_THRESHOLD + ) { + tmpErrors.push({ + code: 'TOO_RISKY', + message: t('operationForm.error.tooRisky'), + }); + } + if ( swapQuote && swapQuote?.priceImpactPercentage >= MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE @@ -100,16 +110,6 @@ const useFormValidation = ({ }); } - if ( - simulatedPool?.userHealthFactor !== undefined && - simulatedPool.userHealthFactor <= HEALTH_FACTOR_LIQUIDATION_THRESHOLD - ) { - tmpErrors.push({ - code: 'TOO_RISKY', - message: t('operationForm.error.tooRisky'), - }); - } - if ( simulatedPool?.userHealthFactor !== undefined && simulatedPool.userHealthFactor < HEALTH_FACTOR_MODERATE_THRESHOLD && From e96efb370bb558feb434717b785342b23e147633 Mon Sep 17 00:00:00 2001 From: therealemjy Date: Mon, 5 Jan 2026 11:34:58 +0100 Subject: [PATCH 08/12] fix: supply cap validation + filter out BNB from repay with collateral flow --- .changeset/bumpy-words-learn.md | 5 -- .changeset/chatty-geese-float.md | 8 --- .changeset/fancy-lines-raise.md | 5 -- .changeset/kind-areas-rescue.md | 2 +- .../queries/getSwapQuote/useGetSwapQuote.ts | 1 + .../BoostForm/__tests__/index.spec.tsx | 20 ++++-- .../Market/OperationForm/BoostForm/index.tsx | 1 + .../OperationForm/BoostForm/useForm/index.tsx | 5 +- .../BoostForm/useForm/useFormValidation.ts | 67 ++++++++++--------- .../Repay/RepayWithCollateralForm/index.tsx | 61 +++++++---------- yarn.lock | 52 ++------------ 11 files changed, 86 insertions(+), 141 deletions(-) delete mode 100644 .changeset/bumpy-words-learn.md delete mode 100644 .changeset/chatty-geese-float.md delete mode 100644 .changeset/fancy-lines-raise.md diff --git a/.changeset/bumpy-words-learn.md b/.changeset/bumpy-words-learn.md deleted file mode 100644 index 2933f67c09..0000000000 --- a/.changeset/bumpy-words-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@venusprotocol/evm": patch ---- - -fix rocket illustration resolution diff --git a/.changeset/chatty-geese-float.md b/.changeset/chatty-geese-float.md deleted file mode 100644 index e7e9cbeab2..0000000000 --- a/.changeset/chatty-geese-float.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@venusprotocol/chains": minor -"@venusprotocol/landing": minor -"@venusprotocol/ui": minor -"@venusprotocol/evm": minor ---- - -tailwind css upgrade to v4 diff --git a/.changeset/fancy-lines-raise.md b/.changeset/fancy-lines-raise.md deleted file mode 100644 index b838cde9ee..0000000000 --- a/.changeset/fancy-lines-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@venusprotocol/evm": patch ---- - -always show user assets only filter diff --git a/.changeset/kind-areas-rescue.md b/.changeset/kind-areas-rescue.md index aaf2e131e3..457ecd9b47 100644 --- a/.changeset/kind-areas-rescue.md +++ b/.changeset/kind-areas-rescue.md @@ -2,4 +2,4 @@ "@venusprotocol/evm": minor --- -improve hgih price impact handling + display USD values of balance updates +improve high price impact handling + display USD values of balance updates diff --git a/apps/evm/src/clients/api/queries/getSwapQuote/useGetSwapQuote.ts b/apps/evm/src/clients/api/queries/getSwapQuote/useGetSwapQuote.ts index 8774c3c56f..efe14e6565 100644 --- a/apps/evm/src/clients/api/queries/getSwapQuote/useGetSwapQuote.ts +++ b/apps/evm/src/clients/api/queries/getSwapQuote/useGetSwapQuote.ts @@ -45,6 +45,7 @@ export const useGetSwapQuote = (input: TrimmedGetSwapQuoteInput, options?: Parti recipientAddress: params.leverageManagerContractAddress, }), ), + retry: false, refetchInterval, ...options, }); diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx index c7169c20d2..16d8970f4e 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/__tests__/index.spec.tsx @@ -53,7 +53,6 @@ const testCases = [ }, }, ], - [ 'user health factor', { @@ -398,14 +397,21 @@ describe('BoostForm', () => { await checkSubmitButtonIsDisabled(); }); - it('disables submit button if amount to supply to open position is higher than asset supply cap', async () => { - const customFakeAsset: Asset = { - ...fakeAsset, - supplyCapTokens: new BigNumber(1000), - supplyBalanceTokens: new BigNumber(999), + it('disables submit button if amount to supply to open position is higher than supplied asset supply cap', async () => { + const customFakePool: Pool = { + ...fakePool, + assets: fakePool.assets.map(asset => + asset.vToken.symbol === 'vUSDT' + ? { + ...asset, + supplyCapTokens: new BigNumber(1000), + supplyBalanceTokens: new BigNumber(999), + } + : asset, + ), }; - const { getByTestId } = renderComponent(, { + const { getByTestId } = renderComponent(, { accountAddress: fakeAccountAddress, }); diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx index 7fcf848ee7..29a564e3f3 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/index.tsx @@ -247,6 +247,7 @@ const BoostForm: React.FC = ({ asset: borrowedAsset, pool }) => const { handleSubmit, isFormValid, formErrors } = useForm({ borrowedAsset, + suppliedAsset, pool, simulatedPool, limitTokens, diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx index fe4616896b..b560091a10 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/index.tsx @@ -10,6 +10,7 @@ export * from './types'; export interface UseFormInput { borrowedAsset: Asset; + suppliedAsset: Asset; pool: Pool; limitTokens: BigNumber; onSubmit: () => Promise; @@ -30,6 +31,7 @@ interface UseFormOutput { const useForm = ({ borrowedAsset, + suppliedAsset, pool, simulatedPool, limitTokens, @@ -42,7 +44,8 @@ const useForm = ({ onSubmit, }: UseFormInput): UseFormOutput => { const { isFormValid, formErrors } = useFormValidation({ - asset: borrowedAsset, + borrowedAsset, + suppliedAsset, pool, limitTokens, simulatedPool, diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts index 36743ae0b8..7cc0f6d5a1 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts @@ -17,7 +17,8 @@ import type { FormError } from '../../types'; import type { FormErrorCode, FormValues } from './types'; interface UseFormValidationInput { - asset: Asset; + borrowedAsset: Asset; + suppliedAsset: Asset; pool: Pool; formValues: FormValues; limitTokens: BigNumber; @@ -33,7 +34,8 @@ interface UseFormValidationOutput { } const useFormValidation = ({ - asset, + borrowedAsset, + suppliedAsset, pool, limitTokens, simulatedPool, @@ -51,21 +53,21 @@ const useFormValidation = ({ tmpErrors.push({ code: 'NO_COLLATERALS', message: t('operationForm.error.noCollateral', { - tokenSymbol: asset.vToken.underlyingToken.symbol, + tokenSymbol: borrowedAsset.vToken.underlyingToken.symbol, }), }); } if ( - asset.borrowCapTokens && - asset.borrowBalanceTokens.isGreaterThanOrEqualTo(asset.borrowCapTokens) + borrowedAsset.borrowCapTokens && + borrowedAsset.borrowBalanceTokens.isGreaterThanOrEqualTo(borrowedAsset.borrowCapTokens) ) { tmpErrors.push({ code: 'BORROW_CAP_ALREADY_REACHED', message: t('operationForm.error.borrowCapReached', { assetBorrowCap: formatTokensToReadableValue({ - value: asset.borrowCapTokens, - token: asset.vToken.underlyingToken, + value: borrowedAsset.borrowCapTokens, + token: borrowedAsset.vToken.underlyingToken, }), }), }); @@ -90,25 +92,27 @@ const useFormValidation = ({ if ( borrowedTokenAmountTokens && - asset.borrowBalanceTokens.plus(borrowedTokenAmountTokens).isGreaterThan(asset.borrowCapTokens) + borrowedAsset.borrowBalanceTokens + .plus(borrowedTokenAmountTokens) + .isGreaterThan(borrowedAsset.borrowCapTokens) ) { tmpErrors.push({ code: 'HIGHER_THAN_BORROW_CAP', message: t('operationForm.error.higherThanBorrowCap', { userMaxBorrowAmount: formatTokensToReadableValue({ - value: asset.borrowCapTokens.minus(asset.borrowBalanceTokens), - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: borrowedAsset.borrowCapTokens.minus(borrowedAsset.borrowBalanceTokens), + token: borrowedAsset.vToken.underlyingToken, + maxDecimalPlaces: borrowedAsset.vToken.underlyingToken.decimals, }), assetBorrowCap: formatTokensToReadableValue({ - value: asset.borrowCapTokens, - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: borrowedAsset.borrowCapTokens, + token: borrowedAsset.vToken.underlyingToken, + maxDecimalPlaces: borrowedAsset.vToken.underlyingToken.decimals, }), assetBorrowBalance: formatTokensToReadableValue({ - value: asset.borrowBalanceTokens, - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: borrowedAsset.borrowBalanceTokens, + token: borrowedAsset.vToken.underlyingToken, + maxDecimalPlaces: borrowedAsset.vToken.underlyingToken.decimals, }), }), }); @@ -116,34 +120,34 @@ const useFormValidation = ({ if ( expectedSuppliedAmountTokens && - asset.supplyBalanceTokens + suppliedAsset.supplyBalanceTokens .plus(expectedSuppliedAmountTokens) - .isGreaterThan(asset.supplyCapTokens) + .isGreaterThan(suppliedAsset.supplyCapTokens) ) { tmpErrors.push({ code: 'HIGHER_THAN_SUPPLY_CAP', message: t('operationForm.error.higherThanSupplyCap', { userMaxSupplyAmount: formatTokensToReadableValue({ - value: asset.supplyCapTokens.minus(asset.supplyBalanceTokens), - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: suppliedAsset.supplyCapTokens.minus(suppliedAsset.supplyBalanceTokens), + token: suppliedAsset.vToken.underlyingToken, + maxDecimalPlaces: suppliedAsset.vToken.underlyingToken.decimals, }), assetSupplyCap: formatTokensToReadableValue({ - value: asset.supplyCapTokens, - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: suppliedAsset.supplyCapTokens, + token: suppliedAsset.vToken.underlyingToken, + maxDecimalPlaces: suppliedAsset.vToken.underlyingToken.decimals, }), assetSupplyBalance: formatTokensToReadableValue({ - value: asset.supplyBalanceTokens, - token: asset.vToken.underlyingToken, - maxDecimalPlaces: asset.vToken.underlyingToken.decimals, + value: suppliedAsset.supplyBalanceTokens, + token: suppliedAsset.vToken.underlyingToken, + maxDecimalPlaces: suppliedAsset.vToken.underlyingToken.decimals, }), }), }); } - const assetLiquidityTokens = new BigNumber(asset.liquidityCents).dividedBy( - asset.tokenPriceCents, + const assetLiquidityTokens = new BigNumber(borrowedAsset.liquidityCents).dividedBy( + borrowedAsset.tokenPriceCents, ); if (borrowedTokenAmountTokens?.isGreaterThan(assetLiquidityTokens)) { @@ -210,7 +214,8 @@ const useFormValidation = ({ return tmpErrors; }, [ - asset, + borrowedAsset, + suppliedAsset, pool, limitTokens, simulatedPool, diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx index 7a4f57726f..fa613f2004 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx @@ -70,22 +70,35 @@ export const RepayWithCollateralForm: React.FC = ( const { mutateAsync: repayWithCollateral, isPending: isRepayWithCollateralLoading } = useRepayWithCollateral(); - const initialFormValues: FormValues = useMemo(() => { - let initialCollateralAsset = repaidAsset; + const tokenBalances = [...pool.assets] + // Sort by user supply balance + .sort((a, b) => compareBigNumbers(a.userSupplyBalanceCents, b.userSupplyBalanceCents, 'desc')) + .reduce((acc, asset) => { + if ( + // Skip vBNB + asset.vToken.symbol === 'vBNB' || + // Skip tokens for which user has no supply + asset.userSupplyBalanceCents.isEqualTo(0) + ) { + return acc; + } - // Find asset with the highest collateral factor and initialize form with it - let highestUserSupplyCents = new BigNumber(0); + const tokenBalance: OptionalTokenBalance = { + token: asset.vToken.underlyingToken, + balanceMantissa: convertTokensToMantissa({ + value: asset.userSupplyBalanceTokens, + token: asset.vToken.underlyingToken, + }), + }; - pool.assets.forEach(a => { - if (a.userSupplyBalanceCents.isGreaterThan(highestUserSupplyCents)) { - highestUserSupplyCents = a.userSupplyBalanceCents; - initialCollateralAsset = a; - } - }); + return [...acc, tokenBalance]; + }, []); + const initialFormValues: FormValues = useMemo(() => { const values: FormValues = { direction: 'exact-in', - collateralToken: initialCollateralAsset.vToken.underlyingToken, + collateralToken: + tokenBalances.length > 0 ? tokenBalances[0].token : repaidAsset.vToken.underlyingToken, collateralAmountTokens: '', repaidAmountTokens: '', acknowledgeRisk: false, @@ -94,7 +107,7 @@ export const RepayWithCollateralForm: React.FC = ( }; return values; - }, [repaidAsset, pool.assets]); + }, [tokenBalances, repaidAsset]); const [formValues, setFormValues] = useState(initialFormValues); @@ -220,30 +233,6 @@ export const RepayWithCollateralForm: React.FC = ( }); const swapQuote = getSwapQuoteData?.swapQuote; - const tokenBalances = [...pool.assets] - // Sort by user supply balance - .sort((a, b) => compareBigNumbers(a.userSupplyBalanceCents, b.userSupplyBalanceCents, 'desc')) - .reduce((acc, asset) => { - if ( - // Skip vBNB - asset.vToken.symbol === 'vBNB' || - // Skip tokens for which user has no supply - asset.userSupplyBalanceCents.isEqualTo(0) - ) { - return acc; - } - - const tokenBalance: OptionalTokenBalance = { - token: asset.vToken.underlyingToken, - balanceMantissa: convertTokensToMantissa({ - value: asset.userSupplyBalanceTokens, - token: asset.vToken.underlyingToken, - }), - }; - - return [...acc, tokenBalance]; - }, []); - const balanceMutations: BalanceMutation[] = [ { type: 'asset', diff --git a/yarn.lock b/yarn.lock index c08705cca0..dd80b5dc4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2560,18 +2560,6 @@ lodash "~4.17.0" tslib "~2.6.0" -"@graphql-codegen/plugin-helpers@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.0.0.tgz#8a913c82a95b9ff36b2180f7c56611cc56268625" - integrity sha512-Z7P89vViJvQakRyMbq/JF2iPLruRFOwOB6IXsuSvV/BptuuEd7fsGPuEf8bdjjDxUY0pJZnFN8oC7jIQ8p9GKA== - dependencies: - "@graphql-tools/utils" "^10.0.0" - change-case-all "1.0.15" - common-tags "1.8.2" - import-from "4.0.0" - lodash "~4.17.0" - tslib "~2.6.0" - "@graphql-codegen/plugin-helpers@^6.1.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.1.0.tgz#251d76dac2801a4baaef5613b9a22698c1218c47" @@ -4743,7 +4731,7 @@ dependencies: semver "^7.3.5" -"@openzeppelin-3/contracts@npm:@openzeppelin/contracts@^3.4.2-solc-0.7": +"@openzeppelin-3/contracts@npm:@openzeppelin/contracts@^3.4.2-solc-0.7", "@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": version "3.4.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== @@ -4758,11 +4746,6 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.5.tgz#572b5da102fc9be1d73f34968e0ca56765969812" integrity sha512-f7L1//4sLlflAN7fVzJLoRedrf5Na3Oal5PZfIq55NFcVZ90EpV1q5xOvL4lFvg3MNICSDr2hH0JUBxwlxcoPg== -"@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" - integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== - "@openzeppelin/contracts@3.4.2-solc-0.7": version "3.4.2-solc-0.7" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" @@ -9902,7 +9885,7 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -dependency-graph@1.0.0: +dependency-graph@1.0.0, dependency-graph@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-1.0.0.tgz#bb5e85aec1310bc13b22dbd76e3196c4ee4c10d2" integrity sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg== @@ -17538,16 +17521,7 @@ string-env-interpolation@^1.0.1: resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152" integrity sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -17629,7 +17603,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -17643,13 +17617,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -19343,7 +19310,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -19361,15 +19328,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From af1dbccd515f92083b327e81c671f13d702cdae0 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Mon, 5 Jan 2026 22:51:03 +0800 Subject: [PATCH 09/12] fix(evm): repay with collateral selection box issue --- .../src/pages/Market/OperationForm/Repay/index.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx index 9e6969b6c6..3129fda4ad 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx @@ -1,4 +1,5 @@ import { Tabs } from 'components'; +import DisabledActionNotice from 'containers/AssetAccessor/DisabledActionNotice'; import { useIsFeatureEnabled } from 'hooks/useIsFeatureEnabled'; import type { Tab } from 'hooks/useTabs'; import { useTranslation } from 'libs/translations'; @@ -39,6 +40,12 @@ export const Repay: React.FC = ({ asset, pool }) => { return repayWithWalletBalanceFormDom; } + const hasCollateral = pool.assets.some( + asset => + // Skip vBNB && Skip tokens for which user has no supply + asset.vToken.symbol !== 'vBNB' && asset.userSupplyBalanceCents.isGreaterThan(0), + ); + const tabs: Tab[] = [ { id: 'repayWithWalletBalance', @@ -48,7 +55,11 @@ export const Repay: React.FC = ({ asset, pool }) => { { id: 'repayWithCollateral', title: t('operationForm.repayTab.collateralTabTitle'), - content: , + content: hasCollateral ? ( + + ) : ( + + ), }, ]; From 673a85b6f9098233ee7ca04d2d069468c7a20d24 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Tue, 6 Jan 2026 22:46:29 +0800 Subject: [PATCH 10/12] fix(evm): vdp-408, change rounding mode to ROUND_DOWN for percentage formatter --- apps/evm/src/libs/translations/translations/en.json | 1 + .../src/pages/Market/OperationForm/Repay/index.tsx | 11 +++-------- .../formatPercentageToReadableValue/index.ts | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/evm/src/libs/translations/translations/en.json b/apps/evm/src/libs/translations/translations/en.json index 1fb2f01b86..4e7accf728 100644 --- a/apps/evm/src/libs/translations/translations/en.json +++ b/apps/evm/src/libs/translations/translations/en.json @@ -726,6 +726,7 @@ }, "repayTab": { "collateralTabTitle": "Collateral", + "noCollateralWarning": "You do not have any collateral to repay with.", "title": "Repay", "walletBalanceTabTitle": "Wallet" }, diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx b/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx index 3129fda4ad..f322708f70 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/index.tsx @@ -1,5 +1,4 @@ -import { Tabs } from 'components'; -import DisabledActionNotice from 'containers/AssetAccessor/DisabledActionNotice'; +import { NoticeWarning, Tabs } from 'components'; import { useIsFeatureEnabled } from 'hooks/useIsFeatureEnabled'; import type { Tab } from 'hooks/useTabs'; import { useTranslation } from 'libs/translations'; @@ -40,11 +39,7 @@ export const Repay: React.FC = ({ asset, pool }) => { return repayWithWalletBalanceFormDom; } - const hasCollateral = pool.assets.some( - asset => - // Skip vBNB && Skip tokens for which user has no supply - asset.vToken.symbol !== 'vBNB' && asset.userSupplyBalanceCents.isGreaterThan(0), - ); + const hasCollateral = pool.userBorrowLimitCents?.isGreaterThan(0); const tabs: Tab[] = [ { @@ -58,7 +53,7 @@ export const Repay: React.FC = ({ asset, pool }) => { content: hasCollateral ? ( ) : ( - + ), }, ]; diff --git a/apps/evm/src/utilities/formatPercentageToReadableValue/index.ts b/apps/evm/src/utilities/formatPercentageToReadableValue/index.ts index fdd3a5b820..9ecd5ea604 100644 --- a/apps/evm/src/utilities/formatPercentageToReadableValue/index.ts +++ b/apps/evm/src/utilities/formatPercentageToReadableValue/index.ts @@ -32,7 +32,7 @@ const formatPercentageToReadableValue = (value: number | string | BigNumber | un readableValue = `${isNegative ? '-' : ''}${absoluteValue.toFormat( decimalPlaces, - BigNumber.ROUND_HALF_UP, + BigNumber.ROUND_DOWN, )}`; } From 9cc436f2e6e835d531bd14700d0cbdfb810c9898 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Wed, 7 Jan 2026 20:53:36 +0800 Subject: [PATCH 11/12] fix(evm): display no quote found error when empty input --- .../BoostForm/useForm/useFormValidation.ts | 14 +++++++------- .../useForm/useFormValidation.ts | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts index 7cc0f6d5a1..fdbbeb1f70 100644 --- a/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/BoostForm/useForm/useFormValidation.ts @@ -73,13 +73,6 @@ const useFormValidation = ({ }); } - if (getSwapQuoteError?.code === 'noSwapQuoteFound') { - tmpErrors.push({ - code: 'NO_SWAP_QUOTE_FOUND', - message: t('operationForm.error.noSwapQuoteFound'), - }); - } - const borrowedTokenAmountTokens = formValues.amountTokens ? new BigNumber(formValues.amountTokens) : undefined; @@ -90,6 +83,13 @@ const useFormValidation = ({ }); } + if (getSwapQuoteError?.code === 'noSwapQuoteFound') { + tmpErrors.push({ + code: 'NO_SWAP_QUOTE_FOUND', + message: t('operationForm.error.noSwapQuoteFound'), + }); + } + if ( borrowedTokenAmountTokens && borrowedAsset.borrowBalanceTokens diff --git a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts index b1c057d036..2fb3aa107b 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/useForm/useFormValidation.ts @@ -66,16 +66,16 @@ const useFormValidation = ({ }); } - if (getSwapQuoteError?.code === 'noSwapQuoteFound') { + if (!collateralAmountTokens?.isGreaterThan(0) || !repaidAmountTokens?.isGreaterThan(0)) { tmpErrors.push({ - code: 'NO_SWAP_QUOTE_FOUND', - message: t('operationForm.error.noSwapQuoteFound'), + code: 'EMPTY_TOKEN_AMOUNT', }); } - if (!collateralAmountTokens?.isGreaterThan(0) || !repaidAmountTokens?.isGreaterThan(0)) { + if (getSwapQuoteError?.code === 'noSwapQuoteFound') { tmpErrors.push({ - code: 'EMPTY_TOKEN_AMOUNT', + code: 'NO_SWAP_QUOTE_FOUND', + message: t('operationForm.error.noSwapQuoteFound'), }); } From 478557399cb88d2a5e3004a294af6fc87c4bb2f3 Mon Sep 17 00:00:00 2001 From: david-sun-venus Date: Wed, 7 Jan 2026 21:20:46 +0800 Subject: [PATCH 12/12] test(evm): update snapshots due to percentage format rounding mode change --- .../__tests__/__snapshots__/index.eMode.spec.tsx.snap | 6 +++--- .../__tests__/__snapshots__/index.spec.tsx.snap | 8 ++++---- .../__tests__/__snapshots__/index.eMode.spec.tsx.snap | 2 +- .../__tests__/__snapshots__/index.spec.tsx.snap | 2 +- .../Pools/__tests__/__snapshots__/index.spec.tsx.snap | 2 +- .../__tests__/__snapshots__/index.spec.tsx.snap | 2 +- .../__tests__/__snapshots__/index.spec.tsx.snap | 4 ++-- .../__tests__/__snapshots__/index.spec.tsx.snap | 10 +++++----- .../Market/__tests__/__snapshots__/index.spec.tsx.snap | 2 +- .../__tests__/__snapshots__/index.eMode.spec.tsx.snap | 2 +- .../Pool/__tests__/__snapshots__/index.spec.tsx.snap | 2 +- .../__tests__/index.spec.ts | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.eMode.spec.tsx.snap b/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.eMode.spec.tsx.snap index 0b1c290457..114e5322b4 100644 --- a/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.eMode.spec.tsx.snap +++ b/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.eMode.spec.tsx.snap @@ -1,7 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`MarketTable - Feature flag enabled: E-mode > renders correctly when user does not have any E-mode group enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.17%-6.48%100 XVS$127.86USDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.17%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable - Feature flag enabled: E-mode > renders correctly when user does not have any E-mode group enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.16%-6.48%100 XVS$127.86USDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.16%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; -exports[`MarketTable - Feature flag enabled: E-mode > renders correctly when user has an E-mode group enabled 1`] = `"Paused assetsMy assets onlyE-mode assets onlyAssetAPY APY CollateralWalletXVS0.17%-6.48%100 XVS$127.86USDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.17%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable - Feature flag enabled: E-mode > renders correctly when user has an E-mode group enabled 1`] = `"Paused assetsMy assets onlyE-mode assets onlyAssetAPY APY CollateralWalletXVS0.16%-6.48%100 XVS$127.86USDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.16%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; -exports[`MarketTable - Feature flag enabled: E-mode > shows E-mode assets only if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyE-mode assets onlyAssetAPY APY CollateralWalletXVS0.17%-6.48%100 XVS$127.86USDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.17%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable - Feature flag enabled: E-mode > shows E-mode assets only if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyE-mode assets onlyAssetAPY APY CollateralWalletXVS0.16%-6.48%100 XVS$127.86USDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.16%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; diff --git a/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.spec.tsx.snap index 11acac92e0..919b5aed2f 100644 --- a/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/containers/MarketTable/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,9 +1,9 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`MarketTable > filters by search input 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletBUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVBUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable > filters by search input 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletBUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVBUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; -exports[`MarketTable > renders with pool data 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.17%-6.48%100 XVS$127.86USDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.17%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable > renders with pool data 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.16%-6.48%100 XVS$127.86USDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.16%APY -6.48%CollateralWallet100 XVS$127.86USDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; -exports[`MarketTable > shows paused assets if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.17%-6.48%100 XVS$127.86USDC5.99%-7.94%-9.18%0 USDC$0USDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.17%APY -6.48%CollateralWallet100 XVS$127.86USDCAPY 5.99%APY -7.94%-9.18%CollateralWallet0 USDC$0USDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable > shows paused assets if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletXVS0.16%-6.48%100 XVS$127.86USDC5.99%-7.94%-9.17%0 USDC$0USDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVXVSAPY 0.16%APY -6.48%CollateralWallet100 XVS$127.86USDCAPY 5.99%APY -7.94%-9.17%CollateralWallet0 USDC$0USDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; -exports[`MarketTable > shows user assets only if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletUSDT4.02%5.77%-5.50%-6.51%900 USDT$900BUSD3.56%5.32%-5.82%110 BUSD$110Sort bySupply APY / LTVUSDTAPY 4.02%5.77%APY -5.50%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.32%APY -5.82%CollateralWallet110 BUSD$110"`; +exports[`MarketTable > shows user assets only if controls are enabled and corresponding toggle is enabled 1`] = `"Paused assetsMy assets onlyAssetAPY APY CollateralWalletUSDT4.01%5.76%-5.49%-6.51%900 USDT$900BUSD3.56%5.31%-5.81%110 BUSD$110Sort bySupply APY / LTVUSDTAPY 4.01%5.76%APY -5.49%-6.51%CollateralWallet900 USDT$900BUSDAPY 3.56%5.31%APY -5.81%CollateralWallet110 BUSD$110"`; diff --git a/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.eMode.spec.tsx.snap b/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.eMode.spec.tsx.snap index cd3fe039c1..cd3793d323 100644 --- a/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.eMode.spec.tsx.snap +++ b/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.eMode.spec.tsx.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Positions - Feature flag enabled: E-mode > displays E-mode banner correctly when user has enabled an E-mode group 1`] = `"VenusHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedE-mode: StablecoinsAssetAPY Balancesorted descending% of limitBUSD-5.82%50 BUSD$500%USDT-5.50%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.82%Balance50 BUSD$50% of limit0%USDTAPY -5.50%-6.51%Balance40 USDT$40% of limit0%AssetsE-mode: StablecoinsSuppliedBorrowedE-mode: StablecoinsAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; +exports[`Positions - Feature flag enabled: E-mode > displays E-mode banner correctly when user has enabled an E-mode group 1`] = `"VenusHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedE-mode: StablecoinsAssetAPY Balancesorted descending% of limitBUSD-5.81%50 BUSD$500%USDT-5.49%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.81%Balance50 BUSD$50% of limit0%USDTAPY -5.49%-6.51%Balance40 USDT$40% of limit0%AssetsE-mode: StablecoinsSuppliedBorrowedE-mode: StablecoinsAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; diff --git a/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.spec.tsx.snap index 5a43d8ba8e..58013b36fb 100644 --- a/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Account/Pools/Positions/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Positions > displays content correctly 1`] = `"VenusHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.82%50 BUSD$500%USDT-5.50%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.82%Balance50 BUSD$50% of limit0%USDTAPY -5.50%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; +exports[`Positions > displays content correctly 1`] = `"VenusHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.81%50 BUSD$500%USDT-5.49%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.81%Balance50 BUSD$50% of limit0%USDTAPY -5.49%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; diff --git a/apps/evm/src/pages/Account/Pools/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Account/Pools/__tests__/__snapshots__/index.spec.tsx.snap index 1a7cf68519..2e6c864a47 100644 --- a/apps/evm/src/pages/Account/Pools/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Account/Pools/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,5 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Pools > displays content correctly 1`] = `"VenusMetaverseHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.82%50 BUSD$500%USDT-5.50%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.82%Balance50 BUSD$50% of limit0%USDTAPY -5.50%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; +exports[`Pools > displays content correctly 1`] = `"VenusMetaverseHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.81%50 BUSD$500%USDT-5.49%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.81%Balance50 BUSD$50% of limit0%USDTAPY -5.49%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; exports[`Pools > displays placeholder when there are no pools to display 1`] = `"No supply or borrow positions yetYour pool positions will appear hereBrowse"`; diff --git a/apps/evm/src/pages/Account/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Account/__tests__/__snapshots__/index.spec.tsx.snap index d9ed0f94f3..7c59f3b805 100644 --- a/apps/evm/src/pages/Account/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Account/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Account > displays content correctly 1`] = `"Net worth$1.23M30D6M1YToday's change+$1.23M99.99%Absolute performance+$1.23MSummaryNet APY0.03%Daily earnings$1.08Total supply$1.23MTotal borrow$123.33Total vault stake$233Minted VAI$10PoolsVaultsVenusMetaverseHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.82%50 BUSD$500%USDT-5.50%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.82%Balance50 BUSD$50% of limit0%USDTAPY -5.50%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.17%90 XVS$115.08USDT4.02%5.77%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.17%Balance90 XVS$115.08CollateralUSDTAPY 4.02%5.77%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; +exports[`Account > displays content correctly 1`] = `"Net worth$1.23M30D6M1YToday's change+$1.23M99.99%Absolute performance+$1.23MSummaryNet APY0.03%Daily earnings$1.08Total supply$1.23MTotal borrow$123.33Total vault stake$233Minted VAI$10PoolsVaultsVenusMetaverseHealth factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.Health factor15.62Net APY0.02%Daily earnings$1Total supply$1.23MTotal borrow$123.33Borrow limit used:6.4%Limit:$1.92K.SuppliedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99CollateralBorrowedAssetAPY Balancesorted descending% of limitBUSD-5.81%50 BUSD$500%USDT-5.49%-6.51%40 USDT$400%Sort byBorrow balanceBUSDAPY -5.81%Balance50 BUSD$50% of limit0%USDTAPY -5.49%-6.51%Balance40 USDT$40% of limit0%AssetsSuppliedBorrowedAssetAPY Balancesorted descendingCollateralXVS0.16%90 XVS$115.08USDT4.01%5.76%100 USDT$100USDC5.99%100 USDC$99.99Sort bySupply balanceXVSAPY 0.16%Balance90 XVS$115.08CollateralUSDTAPY 4.01%5.76%Balance100 USDT$100CollateralUSDCAPY 5.99%Balance100 USDC$99.99Collateral"`; diff --git a/apps/evm/src/pages/IsolatedPools/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/IsolatedPools/__tests__/__snapshots__/index.spec.tsx.snap index b1308406af..c93e88828d 100644 --- a/apps/evm/src/pages/IsolatedPools/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/IsolatedPools/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,5 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Isolated Pools > displays markets table correctly 1`] = `"Paused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.02%5.77%232.51M USDT$31.58M-5.50%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.32%142.66M BUSD$839.1M-5.82%10 BUSD$36.54MXVS> 100T XVS$2.78M0.17%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.02%5.77%Total borrow232.51M USDT$31.58MBorrow APY -5.50%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.32%Total borrow142.66M BUSD$839.1MBorrow APY -5.82%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.17%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; +exports[`Isolated Pools > displays markets table correctly 1`] = `"Paused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.01%5.76%232.51M USDT$31.58M-5.49%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.31%142.66M BUSD$839.1M-5.81%10 BUSD$36.54MXVS> 100T XVS$2.78M0.16%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.01%5.76%Total borrow232.51M USDT$31.58MBorrow APY -5.49%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.31%Total borrow142.66M BUSD$839.1MBorrow APY -5.81%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.16%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; -exports[`Isolated Pools > displays wallet balance column in table when wallet is connected 1`] = `"Paused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.02%5.77%232.51M USDT$31.58M-5.50%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.32%142.66M BUSD$839.1M-5.82%10 BUSD$36.54MXVS> 100T XVS$2.78M0.17%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.02%5.77%Total borrow232.51M USDT$31.58MBorrow APY -5.50%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.32%Total borrow142.66M BUSD$839.1MBorrow APY -5.82%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.17%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; +exports[`Isolated Pools > displays wallet balance column in table when wallet is connected 1`] = `"Paused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.01%5.76%232.51M USDT$31.58M-5.49%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.31%142.66M BUSD$839.1M-5.81%10 BUSD$36.54MXVS> 100T XVS$2.78M0.16%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.01%5.76%Total borrow232.51M USDT$31.58MBorrow APY -5.49%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.31%Total borrow142.66M BUSD$839.1MBorrow APY -5.81%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.16%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; diff --git a/apps/evm/src/pages/Market/OperationForm/ApyBreakdown/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Market/OperationForm/ApyBreakdown/__tests__/__snapshots__/index.spec.tsx.snap index 2743a3615b..8c308b7521 100644 --- a/apps/evm/src/pages/Market/OperationForm/ApyBreakdown/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Market/OperationForm/ApyBreakdown/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,13 +1,13 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`ApyBreakdown > renders correct values: 'borrow' 1`] = `"Borrow APY-4.97%Distribution APY0.52%Total APY6.50%"`; +exports[`ApyBreakdown > renders correct values: 'borrow' 1`] = `"Borrow APY-4.97%Distribution APY0.52%Total APY6.49%"`; -exports[`ApyBreakdown > renders correct values: 'multiple mutations' 1`] = `"Supply APY0.05%Distribution APY0.12%Borrow APY-4.97%Distribution APY0.52%Net APY7.67%"`; +exports[`ApyBreakdown > renders correct values: 'multiple mutations' 1`] = `"Supply APY0.05%Distribution APY0.11%Borrow APY-4.97%Distribution APY0.52%Net APY7.66%"`; exports[`ApyBreakdown > renders correct values: 'no mutations' 1`] = `"Total APY0%"`; -exports[`ApyBreakdown > renders correct values: 'repay' 1`] = `"Borrow APY-4.97%Distribution APY0.52%Total APY6.50%"`; +exports[`ApyBreakdown > renders correct values: 'repay' 1`] = `"Borrow APY-4.97%Distribution APY0.52%Total APY6.49%"`; -exports[`ApyBreakdown > renders correct values: 'supply' 1`] = `"Supply APY0.05%Distribution APY0.12%Total APY1.17%"`; +exports[`ApyBreakdown > renders correct values: 'supply' 1`] = `"Supply APY0.05%Distribution APY0.11%Total APY1.16%"`; -exports[`ApyBreakdown > renders correct values: 'withdraw' 1`] = `"Supply APY3.89%Distribution APY1.35%Prime APY0.75%1.75%Total APY7.99%"`; +exports[`ApyBreakdown > renders correct values: 'withdraw' 1`] = `"Supply APY3.88%Distribution APY1.35%Prime APY0.75%1.75%Total APY7.99%"`; diff --git a/apps/evm/src/pages/Market/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Market/__tests__/__snapshots__/index.spec.tsx.snap index b2fb71a0fa..230902a22f 100644 --- a/apps/evm/src/pages/Market/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Market/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Market > displays content correctly 1`] = `"Supplying XVS to the Venus pool will enable you to borrow tokens from this pool exclusively. Show all marketsSupplyWithdrawBorrowRepayCollateralMAXSupply APY0.05%Distribution APY0.12%Total APY0.17%Connect walletSupply info0%Total supplied> $100T / > $100T> 100T / > 100T XVSCurrent APY0.17%Borrow info< 0.01%Total borrowed$2.36M / > $100T1.85M / > 100T XVSCurrent APY-6.48%Liquidation Threshold50%Liquidation Penalty4%Interest Rate ModelUtilization rateBorrow APYSupply APYE-mode infoStablecoinsCollateralBorrowableCollateralBorrowableMax LTV60%Liquidation threshold62%Liquidation penalty0%GameFiCollateralBorrowableCollateralBorrowableMax LTV60%Liquidation threshold62%Liquidation penalty0%Market infoDaily supplying interests$3.98Daily borrowing interests-$44.81Daily XVS distributed19.99MReserve factor25%Exchange rate1 XVS=49.589181 vXVS"`; +exports[`Market > displays content correctly 1`] = `"Supplying XVS to the Venus pool will enable you to borrow tokens from this pool exclusively. Show all marketsSupplyWithdrawBorrowRepayCollateralMAXSupply APY0.05%Distribution APY0.11%Total APY0.16%Connect walletSupply info0%Total supplied> $100T / > $100T> 100T / > 100T XVSCurrent APY0.16%Borrow info< 0.01%Total borrowed$2.36M / > $100T1.85M / > 100T XVSCurrent APY-6.48%Liquidation Threshold50%Liquidation Penalty4%Interest Rate ModelUtilization rateBorrow APYSupply APYE-mode infoStablecoinsCollateralBorrowableCollateralBorrowableMax LTV60%Liquidation threshold62%Liquidation penalty0%GameFiCollateralBorrowableCollateralBorrowableMax LTV60%Liquidation threshold62%Liquidation penalty0%Market infoDaily supplying interests$3.98Daily borrowing interests-$44.81Daily XVS distributed19.99MReserve factor25%Exchange rate1 XVS=49.589181 vXVS"`; diff --git a/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.eMode.spec.tsx.snap b/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.eMode.spec.tsx.snap index 7f02180261..4076e80b91 100644 --- a/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.eMode.spec.tsx.snap +++ b/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.eMode.spec.tsx.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Pool - Feature flag enabled: E-mode > Assets tab > renders correctly when pool has E-mode groups 1`] = `"AssetsE-modeTotal supply$20.99TTotal borrow$8.58TAvailable liquidity$12.4TAssets4Boost is available now!One-click leverage to boost your yield up to 5x.Learn moreBoost is available now!One-click leverage to boost your yield up to 5x.Venus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Learn moreVenus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Isolated pools are being sunsettedClaim your rewards and close your positionsLearn moreIsolated pools are being sunsettedClaim your rewards and close your positionsBelieve in something?Give your conviction a boost on probable.marketsStart NowBelieve in something?Give your conviction a boost on probable.marketsPaused assetsMy assets onlyE-mode assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.02%5.77%232.51M USDT$31.58M-5.50%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.32%142.66M BUSD$839.1M-5.82%10 BUSD$36.54MXVS> 100T XVS$2.78M0.17%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.02%5.77%Total borrow232.51M USDT$31.58MBorrow APY -5.50%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.32%Total borrow142.66M BUSD$839.1MBorrow APY -5.82%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.17%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; +exports[`Pool - Feature flag enabled: E-mode > Assets tab > renders correctly when pool has E-mode groups 1`] = `"AssetsE-modeTotal supply$20.99TTotal borrow$8.58TAvailable liquidity$12.4TAssets4Boost is available now!One-click leverage to boost your yield up to 5x.Learn moreBoost is available now!One-click leverage to boost your yield up to 5x.Venus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Learn moreVenus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Isolated pools are being sunsettedClaim your rewards and close your positionsLearn moreIsolated pools are being sunsettedClaim your rewards and close your positionsBelieve in something?Give your conviction a boost on probable.marketsStart NowBelieve in something?Give your conviction a boost on probable.marketsPaused assetsMy assets onlyE-mode assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.01%5.76%232.51M USDT$31.58M-5.49%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.31%142.66M BUSD$839.1M-5.81%10 BUSD$36.54MXVS> 100T XVS$2.78M0.16%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.01%5.76%Total borrow232.51M USDT$31.58MBorrow APY -5.49%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.31%Total borrow142.66M BUSD$839.1MBorrow APY -5.81%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.16%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; exports[`Pool - Feature flag enabled: E-mode > E-mode tab > filters assets correctly when using search 1`] = `"AssetsE-modeEnabling E-Mode allows you to maximize your borrowing power, however, borrowing is restricted to assets within the selected group. Learn moreSort by:Max LTVStablecoinsDisableStablecoinsDisableAssetCollateralBorrowableMax LTVsorted descendingThresholdPenaltySort byMax LTVDeFiHealth factor:15.621.66ModerateSwitchHealth factor:15.621.66ModerateBUSDCollateralBorrowableMax LTV90%Liquidation threshold92%Liquidation penalty30%DeFiHealth factor:15.621.66ModerateSwitchHealth factor:15.621.66ModerateAssetCollateralBorrowableMax LTVsorted descendingThresholdPenaltyBUSD90%92%30%Sort byMax LTVBUSDCollateralBorrowableMax LTV90%Threshold92%Penalty30%"`; diff --git a/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.spec.tsx.snap b/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.spec.tsx.snap index ff106377c4..fe6fecfad3 100644 --- a/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.spec.tsx.snap +++ b/apps/evm/src/pages/Pool/__tests__/__snapshots__/index.spec.tsx.snap @@ -1,3 +1,3 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Pool > renders correctly 1`] = `"Total supply$20.99TTotal borrow$8.58TAvailable liquidity$12.4TAssets4Boost is available now!One-click leverage to boost your yield up to 5x.Learn moreBoost is available now!One-click leverage to boost your yield up to 5x.Venus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Learn moreVenus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Isolated pools are being sunsettedClaim your rewards and close your positionsLearn moreIsolated pools are being sunsettedClaim your rewards and close your positionsBelieve in something?Give your conviction a boost on probable.marketsStart NowBelieve in something?Give your conviction a boost on probable.marketsPaused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.02%5.77%232.51M USDT$31.58M-5.50%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.32%142.66M BUSD$839.1M-5.82%10 BUSD$36.54MXVS> 100T XVS$2.78M0.17%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.02%5.77%Total borrow232.51M USDT$31.58MBorrow APY -5.50%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.32%Total borrow142.66M BUSD$839.1MBorrow APY -5.82%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.17%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; +exports[`Pool > renders correctly 1`] = `"Total supply$20.99TTotal borrow$8.58TAvailable liquidity$12.4TAssets4Boost is available now!One-click leverage to boost your yield up to 5x.Learn moreBoost is available now!One-click leverage to boost your yield up to 5x.Venus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Learn moreVenus is live on Binance Wallet Earn.Borrow USDT and share $400,000 in rewards!Isolated pools are being sunsettedClaim your rewards and close your positionsLearn moreIsolated pools are being sunsettedClaim your rewards and close your positionsBelieve in something?Give your conviction a boost on probable.marketsStart NowBelieve in something?Give your conviction a boost on probable.marketsPaused assetsMy assets onlyAssetTotal supplySupply APY sorted descendingTotal borrowBorrow APY LiquidityUSDT> 100T USDT$10.98T4.01%5.76%232.51M USDT$31.58M-5.49%-6.51%10 USDT$55.34MBUSD> 100T BUSD$10.54B3.56%5.31%142.66M BUSD$839.1M-5.81%10 BUSD$36.54MXVS> 100T XVS$2.78M0.16%1.85M XVS$709.25K-6.48%10 XVS$80.36MSort bySupply APY / LTVUSDTTotal supply> 100T USDT$10.98TSupply APY 4.01%5.76%Total borrow232.51M USDT$31.58MBorrow APY -5.49%-6.51%Liquidity10 USDT$55.34MBUSDTotal supply> 100T BUSD$10.54BSupply APY 3.56%5.31%Total borrow142.66M BUSD$839.1MBorrow APY -5.81%Liquidity10 BUSD$36.54MXVSTotal supply> 100T XVS$2.78MSupply APY 0.16%Total borrow1.85M XVS$709.25KBorrow APY -6.48%Liquidity10 XVS$80.36M"`; diff --git a/apps/evm/src/utilities/formatPercentageToReadableValue/__tests__/index.spec.ts b/apps/evm/src/utilities/formatPercentageToReadableValue/__tests__/index.spec.ts index 5604dee252..bc5881aac2 100644 --- a/apps/evm/src/utilities/formatPercentageToReadableValue/__tests__/index.spec.ts +++ b/apps/evm/src/utilities/formatPercentageToReadableValue/__tests__/index.spec.ts @@ -50,6 +50,6 @@ describe('utilities/formatPercentageToReadableValue', () => { it('should handle a string number', () => { const value = '200.567'; const result = formatPercentageToReadableValue(value); - expect(result).toBe('200.57%'); + expect(result).toBe('200.56%'); }); });