diff --git a/.changeset/dry-years-kick.md b/.changeset/dry-years-kick.md new file mode 100644 index 0000000000..e4aae4a50f --- /dev/null +++ b/.changeset/dry-years-kick.md @@ -0,0 +1,5 @@ +--- +"@venusprotocol/evm": minor +--- + +expand geo-blocker feature to allow users to close restricted positions diff --git a/apps/evm/src/containers/AssetAccessor/__tests__/index.spec.tsx b/apps/evm/src/containers/AssetAccessor/__tests__/index.spec.tsx index d5b07939ef..753513be3c 100644 --- a/apps/evm/src/containers/AssetAccessor/__tests__/index.spec.tsx +++ b/apps/evm/src/containers/AssetAccessor/__tests__/index.spec.tsx @@ -31,6 +31,16 @@ const supplyProps: Omit = { action: 'supply', }; +const withdrawProps: Omit = { + ...borrowProps, + action: 'withdraw', +}; + +const repayProps: Omit = { + ...borrowProps, + action: 'repay', +}; + const fakeChildrenContent = 'Fake content'; const TestComponent = () => <>{fakeChildrenContent}; @@ -116,6 +126,44 @@ describe('containers/AssetAccessor', () => { expect(queryByText(fakeChildrenContent)).toBeNull(); }); + it('renders children for a restricted asset when the user withdraws an existing supply position', async () => { + mockGetPool( + getCustomFakePool({ + asset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(1), + }, + }), + ); + + const { getByText, queryByText } = renderComponent( + {() => }, + ); + + await waitFor(() => expect(getByText(fakeChildrenContent)).toBeInTheDocument()); + + expect(queryByText(en.assetAccessor.assetNotAvailable)).toBeNull(); + }); + + it('renders children for a restricted asset when the user repays an existing borrow position', async () => { + mockGetPool( + getCustomFakePool({ + asset: { + isRestricted: true, + userBorrowBalanceCents: new BigNumber(1), + }, + }), + ); + + const { getByText, queryByText } = renderComponent( + {() => }, + ); + + await waitFor(() => expect(getByText(fakeChildrenContent)).toBeInTheDocument()); + + expect(queryByText(en.assetAccessor.assetNotAvailable)).toBeNull(); + }); + it('renders default token announcement if a disabled borrow action has no token announcement', async () => { mockGetPool( getCustomFakePool({ diff --git a/apps/evm/src/containers/AssetAccessor/index.tsx b/apps/evm/src/containers/AssetAccessor/index.tsx index 142e7e7f74..27fcd568e8 100644 --- a/apps/evm/src/containers/AssetAccessor/index.tsx +++ b/apps/evm/src/containers/AssetAccessor/index.tsx @@ -36,7 +36,17 @@ const AssetAccessor: React.FC = ({ return ; } - if (asset.isRestricted) { + let isActionRestricted = asset.isRestricted; + + // Allow user to close a position with an asset that's now restricted for them + if ( + (action === 'withdraw' && asset.userSupplyBalanceCents?.isGreaterThan(0)) || + (action === 'repay' && asset.userBorrowBalanceCents?.isGreaterThan(0)) + ) { + isActionRestricted = false; + } + + if (isActionRestricted) { return ; } 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 32b7f1096d..9686a0c93d 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 @@ -22,6 +22,7 @@ import { HIGH_PRICE_IMPACT_THRESHOLD_PERCENTAGE, MAXIMUM_PRICE_IMPACT_THRESHOLD_PERCENTAGE, } from 'constants/swap'; +import useDelegateApproval from 'hooks/useDelegateApproval'; import { useSimulateBalanceMutations } from 'hooks/useSimulateBalanceMutations'; import { defaultUserChainSettings, useUserChainSettings } from 'hooks/useUserChainSettings'; import { VError } from 'libs/errors'; @@ -31,13 +32,14 @@ import { checkSubmitButtonIsEnabled, } from 'pages/Market/OperationForm/__testUtils__/checkFns'; import { renderComponent } from 'testUtils/render'; -import { type Asset, ChainId, type SwapQuote } from 'types'; +import { type Asset, ChainId, type Pool, type SwapQuote } from 'types'; import { convertTokensToMantissa } from 'utilities'; import { RepayWithCollateralForm } from '..'; import { fakeAsset, fakePool } from '../../__testUtils__/fakeData'; import TEST_IDS from '../testIds'; vi.mock('hooks/useTokenApproval'); +vi.mock('hooks/useDelegateApproval'); const fakeRepaidAsset = fakeAsset; const fakeCollateralAsset = fakePool.assets[2]; @@ -84,6 +86,8 @@ const getLastUseGetSwapQuoteCallArgs = () => describe('RepayWithCollateralForm', () => { beforeEach(() => { + mockRepayWithCollateral.mockReset(); + (useUserChainSettings as Mock).mockReturnValue([ { ...defaultUserChainSettings, @@ -96,6 +100,13 @@ describe('RepayWithCollateralForm', () => { mutateAsync: mockRepayWithCollateral, })); + (useDelegateApproval as Mock).mockReturnValue({ + isDelegateApproved: true, + isDelegateApprovedLoading: false, + isUpdateDelegateStatusLoading: false, + updatePoolDelegateStatus: vi.fn(), + }); + (useGetSwapQuote as Mock).mockImplementation( (input: TrimmedGetSwapQuoteInput, { enabled }: UseQueryOptions) => ({ isLoading: false, @@ -767,6 +778,64 @@ describe('RepayWithCollateralForm', () => { expect(mockRepayWithCollateral.mock.calls[0]).toMatchSnapshot(); }); + it('lets user use a restricted asset as collateral when repaying that same market', async () => { + const restrictedRepaidAsset: Asset = { + ...fakeRepaidAsset, + isRestricted: true, + }; + const restrictedPool: Pool = { + ...fakePool, + assets: fakePool.assets.map(asset => + asset.vToken.address === restrictedRepaidAsset.vToken.address + ? { + ...asset, + isRestricted: true, + } + : asset, + ), + }; + + const { getByTestId, getByText, container } = renderComponent( + , + { + accountAddress: fakeAccountAddress, + }, + ); + + selectToken({ + container, + selectTokenTextFieldTestId: TEST_IDS.selectCollateralTokenTextField, + token: restrictedRepaidAsset.vToken.underlyingToken, + }); + + const collateralTokenInput = getByTestId( + getTokenTextFieldTestId({ + parentTestId: TEST_IDS.selectCollateralTokenTextField, + }), + ) as HTMLInputElement; + + fireEvent.change(collateralTokenInput, { + target: { value: 1 }, + }); + + await checkSubmitButtonIsEnabled({ + textContent: en.operationForm.submitButtonLabel.repay, + }); + + fireEvent.click(getByText(en.operationForm.submitButtonLabel.repay)); + + await waitFor(() => expect(mockRepayWithCollateral).toHaveBeenCalledTimes(1)); + expect(mockRepayWithCollateral.mock.calls[0]).toEqual([ + expect.objectContaining({ + amountMantissa: 1000000000000000000n, + vToken: expect.objectContaining({ + address: restrictedRepaidAsset.vToken.address, + underlyingToken: restrictedRepaidAsset.vToken.underlyingToken, + }), + }), + ]); + }); + it('lets user repay full loan using a swap', async () => { const { getByText, container } = renderComponent( , 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 3bdc34c9a0..2020b7e0e4 100644 --- a/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx +++ b/apps/evm/src/pages/Market/OperationForm/Repay/RepayWithCollateralForm/index.tsx @@ -74,13 +74,16 @@ export const RepayWithCollateralForm: React.FC = ( // Sort by user supply balance .sort((a, b) => compareBigNumbers(a.userSupplyBalanceCents, b.userSupplyBalanceCents, 'desc')) .reduce((acc, asset) => { + // Allow user to use restricted collateral asset to repay the same asset + const isRestricted = asset.isRestricted && !areTokensEqual(asset.vToken, repaidAsset.vToken); + if ( // Skip vBNB asset.vToken.symbol === 'vBNB' || // Skip tokens for which user has no supply asset.userSupplyBalanceCents.isEqualTo(0) || // Skip restricted assets - asset.isRestricted + isRestricted ) { return acc; } diff --git a/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/__tests__/index.spec.ts b/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/__tests__/index.spec.ts index ab2025988a..fcfd878404 100644 --- a/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/__tests__/index.spec.ts +++ b/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/__tests__/index.spec.ts @@ -22,11 +22,11 @@ describe('useGetOperationFormTokenBalances', () => { }); }); - it('filters out restricted assets and preserves gated asset metadata', () => { - const allowedAsset = { + it('keeps the selected restricted asset, filters out other restricted assets, and preserves gated asset metadata', () => { + const restrictedUnderlyingAsset = { ...assetData[0], disabledTokenActions: [], - isRestricted: false, + isRestricted: true, isGated: false, }; const gatedAsset = { @@ -35,7 +35,7 @@ describe('useGetOperationFormTokenBalances', () => { isRestricted: false, isGated: true, }; - const restrictedAsset = { + const restrictedNonUnderlyingAsset = { ...assetData[3], disabledTokenActions: [], isRestricted: true, @@ -45,7 +45,7 @@ describe('useGetOperationFormTokenBalances', () => { (useGetPool as Mock).mockReturnValue({ data: { pool: { - assets: [allowedAsset, gatedAsset, restrictedAsset], + assets: [restrictedUnderlyingAsset, gatedAsset, restrictedNonUnderlyingAsset], }, }, }); @@ -54,7 +54,7 @@ describe('useGetOperationFormTokenBalances', () => { useGetOperationFormTokenBalances({ poolComptrollerContractAddress: fakeAccountAddress, accountAddress: fakeAccountAddress, - underlyingToken: allowedAsset.vToken.underlyingToken, + underlyingToken: restrictedUnderlyingAsset.vToken.underlyingToken, isIntegratedSwapFeatureEnabled: true, canWrapNativeToken: false, action: 'supply', @@ -63,7 +63,7 @@ describe('useGetOperationFormTokenBalances', () => { expect(result.current.tokenBalances).toEqual([ expect.objectContaining({ - token: allowedAsset.vToken.underlyingToken, + token: restrictedUnderlyingAsset.vToken.underlyingToken, isGated: false, balanceMantissa: expect.any(BigNumber), }), diff --git a/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/index.ts b/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/index.ts index 5518e29630..f394af9579 100644 --- a/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/index.ts +++ b/apps/evm/src/pages/Market/OperationForm/useGetOperationFormTokenBalances/index.ts @@ -53,7 +53,10 @@ export const useGetOperationFormTokenBalances = ({ const isPaused = asset.disabledTokenActions.includes(action); - if (shouldIncludeTokenBalance && !isPaused && !asset.isRestricted) { + const isRestricted = + asset.isRestricted && !areTokensEqual(asset.vToken.underlyingToken, underlyingToken); + + if (shouldIncludeTokenBalance && !isPaused && !isRestricted) { tokenBalances.push({ token: asset.vToken.underlyingToken, balanceMantissa: convertTokensToMantissa({ diff --git a/apps/evm/src/pages/Trade/PairInfo/index.tsx b/apps/evm/src/pages/Trade/PairInfo/index.tsx index a6afda8e80..1a697ecf09 100644 --- a/apps/evm/src/pages/Trade/PairInfo/index.tsx +++ b/apps/evm/src/pages/Trade/PairInfo/index.tsx @@ -73,6 +73,10 @@ export const PairInfo: React.FC = ({ changePercentage, priceCents acc.longAsset = asset; } + if (asset.isRestricted) { + return acc; + } + const tokenBalance: OptionalTokenBalance = { token: asset.vToken.underlyingToken, isDeemed: asset.disabledTokenActions.includes('supply'), @@ -99,6 +103,10 @@ export const PairInfo: React.FC = ({ changePercentage, priceCents acc.shortAsset = asset; } + if (asset.isRestricted) { + return acc; + } + const tokenBalance: OptionalTokenBalance = { token: asset.vToken.underlyingToken, isDeemed: asset.disabledTokenActions.includes('borrow') || !asset.isBorrowable, diff --git a/apps/evm/src/pages/Trade/PositionForm/__tests__/index.spec.tsx b/apps/evm/src/pages/Trade/PositionForm/__tests__/index.spec.tsx index 9d03f8b0be..a41468f251 100644 --- a/apps/evm/src/pages/Trade/PositionForm/__tests__/index.spec.tsx +++ b/apps/evm/src/pages/Trade/PositionForm/__tests__/index.spec.tsx @@ -1,7 +1,11 @@ import { screen } from '@testing-library/react'; +import BigNumber from 'bignumber.js'; +import type { Mock } from 'vitest'; import { tradePositions } from '__mocks__/models/trade'; +import { useGetProportionalCloseTolerancePercentage } from 'clients/api'; import { en } from 'libs/translations'; +import { MINIMUM_LEVERAGE_FACTOR } from 'pages/Trade/constants'; import { renderComponent } from 'testUtils/render'; import type { TokenAction, TradePosition } from 'types'; import { type FormProps, PositionForm } from '..'; @@ -22,6 +26,8 @@ vi.mock('../Form', () => ({ })); const basePosition = tradePositions[0]; +const mockUseGetProportionalCloseTolerancePercentage = + useGetProportionalCloseTolerancePercentage as Mock; const baseProps: FormProps = { action: 'open', @@ -43,26 +49,33 @@ const baseProps: FormProps = { }; const getPosition = ({ - dsaDisabledTokenActions = basePosition.dsaAsset.disabledTokenActions, - longDisabledTokenActions = basePosition.longAsset.disabledTokenActions, - shortDisabledTokenActions = basePosition.shortAsset.disabledTokenActions, + dsaAsset = {}, + longAsset = {}, + shortAsset = {}, }: { - dsaDisabledTokenActions?: TokenAction[]; - longDisabledTokenActions?: TokenAction[]; - shortDisabledTokenActions?: TokenAction[]; + dsaAsset?: Partial; + longAsset?: Partial; + shortAsset?: Partial; } = {}): TradePosition => ({ ...basePosition, dsaAsset: { ...basePosition.dsaAsset, - disabledTokenActions: dsaDisabledTokenActions, + disabledTokenActions: [] as TokenAction[], + isRestricted: false, + ...dsaAsset, }, longAsset: { ...basePosition.longAsset, - disabledTokenActions: longDisabledTokenActions, + disabledTokenActions: [] as TokenAction[], + isRestricted: false, + ...longAsset, }, shortAsset: { ...basePosition.shortAsset, - disabledTokenActions: shortDisabledTokenActions, + disabledTokenActions: [] as TokenAction[], + isRestricted: false, + isBorrowable: true, + ...shortAsset, }, }); @@ -75,8 +88,18 @@ const renderPositionForm = ({ } = {}) => renderComponent(); describe('PositionForm', () => { + beforeEach(() => { + mockUseGetProportionalCloseTolerancePercentage.mockImplementation(() => ({ + data: { + proportionalCloseTolerancePercentage: 2, + }, + })); + }); + it('renders Form when no warning applies', () => { - renderPositionForm(); + renderPositionForm({ + position: getPosition(), + }); expect(screen.getByTestId('position-form')).toBeInTheDocument(); expect(screen.getByText(baseProps.action)).toBeInTheDocument(); @@ -88,42 +111,54 @@ describe('PositionForm', () => { { action: 'supplyDsa' as const, position: getPosition({ - dsaDisabledTokenActions: ['supply'], + dsaAsset: { + disabledTokenActions: ['supply'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotSupplyDsa, }, { action: 'withdrawDsa' as const, position: getPosition({ - dsaDisabledTokenActions: ['withdraw'], + dsaAsset: { + disabledTokenActions: ['withdraw'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotWithdrawDsa, }, { action: 'open' as const, position: getPosition({ - longDisabledTokenActions: ['supply'], + longAsset: { + disabledTokenActions: ['supply'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotSupplyLong, }, { action: 'close' as const, position: getPosition({ - longDisabledTokenActions: ['withdraw'], + longAsset: { + disabledTokenActions: ['withdraw'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotWithdrawLong, }, { action: 'increase' as const, position: getPosition({ - shortDisabledTokenActions: ['borrow'], + shortAsset: { + disabledTokenActions: ['borrow'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotBorrowShort, }, { action: 'reduce' as const, position: getPosition({ - shortDisabledTokenActions: ['repay'], + shortAsset: { + disabledTokenActions: ['repay'], + }, }), expectedWarning: en.trade.operationForm.warning.cannotRepayShort, }, @@ -144,9 +179,15 @@ describe('PositionForm', () => { renderPositionForm({ action: 'close', position: getPosition({ - dsaDisabledTokenActions: ['withdraw'], - longDisabledTokenActions: ['withdraw'], - shortDisabledTokenActions: ['repay'], + dsaAsset: { + disabledTokenActions: ['withdraw'], + }, + longAsset: { + disabledTokenActions: ['withdraw'], + }, + shortAsset: { + disabledTokenActions: ['repay'], + }, }), }); @@ -155,4 +196,130 @@ describe('PositionForm', () => { ); expect(screen.queryByTestId('position-form')).not.toBeInTheDocument(); }); + + it.each([ + { + action: 'supplyDsa' as const, + position: getPosition({ + dsaAsset: { + isRestricted: true, + }, + }), + expectedWarning: en.trade.operationForm.warning.cannotSupplyDsa, + }, + { + action: 'withdrawDsa' as const, + position: getPosition({ + dsaAsset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(0), + }, + }), + expectedWarning: en.trade.operationForm.warning.cannotWithdrawDsa, + }, + { + action: 'open' as const, + position: getPosition({ + longAsset: { + isRestricted: true, + }, + }), + expectedWarning: en.trade.operationForm.warning.cannotSupplyLong, + }, + { + action: 'increase' as const, + position: getPosition({ + shortAsset: { + isRestricted: true, + }, + }), + expectedWarning: en.trade.operationForm.warning.cannotBorrowShort, + }, + { + action: 'reduce' as const, + position: getPosition({ + shortAsset: { + isRestricted: true, + userBorrowBalanceCents: new BigNumber(0), + }, + }), + expectedWarning: en.trade.operationForm.warning.cannotRepayShort, + }, + ])( + 'renders a warning for $action when the required token is restricted', + ({ action, position, expectedWarning }) => { + renderPositionForm({ + action, + position, + }); + + expect(screen.getByTestId('notice-warning')).toHaveTextContent(expectedWarning); + expect(screen.queryByTestId('position-form')).not.toBeInTheDocument(); + }, + ); + + it('renders Form when closing a restricted position with existing balances', () => { + renderPositionForm({ + action: 'close', + position: getPosition({ + dsaAsset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(1), + }, + longAsset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(1), + }, + shortAsset: { + isRestricted: true, + userBorrowBalanceCents: new BigNumber(1), + }, + }), + }); + + expect(screen.getByTestId('position-form')).toBeInTheDocument(); + expect(screen.queryByTestId('notice-warning')).not.toBeInTheDocument(); + }); + + it('renders Form when reducing a restricted position with existing balances', () => { + renderPositionForm({ + action: 'reduce', + position: getPosition({ + dsaAsset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(1), + }, + longAsset: { + isRestricted: true, + userSupplyBalanceCents: new BigNumber(1), + }, + shortAsset: { + isRestricted: true, + userBorrowBalanceCents: new BigNumber(1), + }, + }), + }); + + expect(screen.getByTestId('position-form')).toBeInTheDocument(); + expect(screen.queryByTestId('notice-warning')).not.toBeInTheDocument(); + }); + + it('renders a leverage warning for open when the pair cannot reach the minimum leverage factor', () => { + renderPositionForm({ + action: 'open', + position: getPosition({ + dsaAsset: { + collateralFactor: 0.2, + }, + longAsset: { + collateralFactor: 0.2, + }, + }), + }); + + expect(screen.getByTestId('notice-warning')).toHaveTextContent( + `This token pair does not allow a leverage factor of at least ${MINIMUM_LEVERAGE_FACTOR}`, + ); + expect(screen.queryByTestId('position-form')).not.toBeInTheDocument(); + }); }); diff --git a/apps/evm/src/pages/Trade/PositionForm/index.tsx b/apps/evm/src/pages/Trade/PositionForm/index.tsx index f398fe93e1..07b30dceae 100644 --- a/apps/evm/src/pages/Trade/PositionForm/index.tsx +++ b/apps/evm/src/pages/Trade/PositionForm/index.tsx @@ -16,14 +16,34 @@ export const PositionForm: React.FC = ({ action, position, ...otherPr const proportionalCloseTolerancePercentage = getProportionalCloseTolerancePercentageData?.proportionalCloseTolerancePercentage; - const canSupplyDsa = !position.dsaAsset.disabledTokenActions.includes('supply'); - const canWithdrawDsa = !position.dsaAsset.disabledTokenActions.includes('withdraw'); - const canSupplyLong = !position.longAsset.disabledTokenActions.includes('supply'); - const canWithdrawLong = !position.longAsset.disabledTokenActions.includes('withdraw'); + const canSupplyDsa = + !position.dsaAsset.disabledTokenActions.includes('supply') && !position.dsaAsset.isRestricted; + + const canWithdrawDsa = + !position.dsaAsset.disabledTokenActions.includes('withdraw') && + (!position.dsaAsset.isRestricted || + position.dsaAsset.userSupplyBalanceCents?.isGreaterThan(0) || + action === 'close'); + + const canSupplyLong = + !position.longAsset.disabledTokenActions.includes('supply') && !position.longAsset.isRestricted; + + const canWithdrawLong = + !position.longAsset.disabledTokenActions.includes('withdraw') && + (!position.longAsset.isRestricted || + position.longAsset.userSupplyBalanceCents?.isGreaterThan(0) || + action === 'close'); + const canBorrowShort = !position.shortAsset.disabledTokenActions.includes('borrow') && - position.shortAsset.isBorrowable; - const canRepayShort = !position.shortAsset.disabledTokenActions.includes('repay'); + position.shortAsset.isBorrowable && + !position.shortAsset.isRestricted; + + const canRepayShort = + !position.shortAsset.disabledTokenActions.includes('repay') && + (!position.shortAsset.isRestricted || + position.shortAsset.userBorrowBalanceCents?.isGreaterThan(0) || + action === 'close'); let warningMessage: undefined | string; diff --git a/apps/evm/src/pages/Trade/useGetTradeAssets/__tests__/index.spec.ts b/apps/evm/src/pages/Trade/useGetTradeAssets/__tests__/index.spec.ts index c2824855e1..b7c8c58453 100644 --- a/apps/evm/src/pages/Trade/useGetTradeAssets/__tests__/index.spec.ts +++ b/apps/evm/src/pages/Trade/useGetTradeAssets/__tests__/index.spec.ts @@ -167,36 +167,4 @@ describe('useGetTradeAssets', () => { dsaAssets: [], }); }); - - it('filters restricted assets out of borrow, supply, and DSA lists', () => { - const restrictedAsset = { - ...poolData[0].assets[0], - isRestricted: true, - }; - const unrestrictedAsset = poolData[0].assets[2]; - const poolWithRestrictedAsset = { - ...poolData[0], - assets: [restrictedAsset, unrestrictedAsset], - }; - - (useGetPool as Mock).mockImplementation(() => ({ - isLoading: false, - data: { - pool: poolWithRestrictedAsset, - }, - })); - - (useGetDsaVTokens as Mock).mockImplementation(() => ({ - isLoading: false, - data: { - dsaVTokenAddresses: poolWithRestrictedAsset.assets.map(asset => asset.vToken.address), - }, - })); - - const { result } = renderHook(() => useGetTradeAssets()); - - expect(result.current.data.borrowAssets).toEqual([unrestrictedAsset]); - expect(result.current.data.supplyAssets).toEqual([unrestrictedAsset]); - expect(result.current.data.dsaAssets).toEqual([unrestrictedAsset]); - }); }); diff --git a/apps/evm/src/pages/Trade/useGetTradeAssets/index.ts b/apps/evm/src/pages/Trade/useGetTradeAssets/index.ts index fa587b99ef..ac2b34436d 100644 --- a/apps/evm/src/pages/Trade/useGetTradeAssets/index.ts +++ b/apps/evm/src/pages/Trade/useGetTradeAssets/index.ts @@ -26,7 +26,7 @@ export const useGetTradeAssets = (input?: { accountAddress?: Address }) => { !isGetPoolLoading && !isGetDsaVTokensLoading && !!corePool && !!dsaVTokenAddresses; const assets = isDataReady - ? corePool.assets.filter(asset => !asset.vToken.underlyingToken.isNative && !asset.isRestricted) + ? corePool.assets.filter(asset => !asset.vToken.underlyingToken.isNative) : []; const dsaAssets = isDataReady