From b4ab94b54b0b4bf8950385f73cf7dfc82785b9b2 Mon Sep 17 00:00:00 2001 From: macqbat Date: Wed, 9 Nov 2022 09:23:23 +0100 Subject: [PATCH] chore: filter assets to withdraw (#1974) * feat: filter assets to withdraw * feat: filter assets to withdraw - add some test * feat: filter assets to withdraw - add some test * feat: filter assets to withdraw - add logic for filtering out zero balanced accounts * feat: filter assets to withdraw - add logic for filtering out zero balanced accounts Co-authored-by: maciek --- .../src/integration/withdraw.cy.ts | 4 +- .../src/lib/withdraw-form-container.spec.tsx | 234 ++++++++++++++++++ .../src/lib/withdraw-form-container.tsx | 34 ++- 3 files changed, 252 insertions(+), 20 deletions(-) create mode 100644 libs/withdraws/src/lib/withdraw-form-container.spec.tsx diff --git a/apps/trading-e2e/src/integration/withdraw.cy.ts b/apps/trading-e2e/src/integration/withdraw.cy.ts index 202d10a40..a09438e15 100644 --- a/apps/trading-e2e/src/integration/withdraw.cy.ts +++ b/apps/trading-e2e/src/integration/withdraw.cy.ts @@ -10,7 +10,7 @@ describe('withdraw', { tags: '@smoke' }, () => { const submitWithdrawBtn = 'submit-withdrawal'; const ethAddressValue = Cypress.env('ETHEREUM_WALLET_ADDRESS'); const asset1Name = 'Sepolia tBTC'; - const asset2Name = 'Sepolia tUSDC'; + const asset2Name = 'Euro'; beforeEach(() => { cy.mockWeb3Provider(); @@ -52,7 +52,7 @@ describe('withdraw', { tags: '@smoke' }, () => { }); it('max amount', () => { selectAsset(asset2Name); // Will be above maximum because the vega wallet doesnt have any collateral - cy.get(amountField).clear().type('1'); + cy.get(amountField).clear().type('1001', { delay: 100 }); cy.getByTestId(submitWithdrawBtn).click(); cy.get('[data-testid="input-error-text"]').should( 'contain.text', diff --git a/libs/withdraws/src/lib/withdraw-form-container.spec.tsx b/libs/withdraws/src/lib/withdraw-form-container.spec.tsx new file mode 100644 index 000000000..1e2e7cb0e --- /dev/null +++ b/libs/withdraws/src/lib/withdraw-form-container.spec.tsx @@ -0,0 +1,234 @@ +import { render, screen } from '@testing-library/react'; +import { MockedProvider } from '@apollo/client/testing'; +import type { Account } from '@vegaprotocol/accounts'; +import { WithdrawFormContainer } from './withdraw-form-container'; +import { Schema as Types } from '@vegaprotocol/types'; +import { useWeb3React } from '@web3-react/core'; +let mockData: Account[] | null = null; +jest.mock('@vegaprotocol/react-helpers', () => ({ + ...jest.requireActual('@vegaprotocol/react-helpers'), + useDataProvider: () => ({ + data: mockData, + }), +})); +jest.mock('@web3-react/core'); + +describe('WithdrawFormContainer', () => { + const props = { + submit: jest.fn(), + assetId: 'assetId', + partyId: 'partyId', + }; + const MOCK_ETH_ADDRESS = '0xcool'; + + const account1: Account = { + type: Types.AccountType.ACCOUNT_TYPE_GENERAL, + balance: '200099689', + market: null, + asset: { + id: 'assetId-1', + name: 'tBTC TEST', + symbol: 'tBTC', + decimals: 5, + quantum: '1', + source: { + __typename: 'ERC20', + contractAddress: '0x1d525fB145Af5c51766a89706C09fE07E6058D1D', + lifetimeLimit: '0', + withdrawThreshold: '0', + }, + status: Types.AssetStatus.STATUS_ENABLED, + infrastructureFeeAccount: { + balance: '1', + __typename: 'AccountBalance', + }, + globalRewardPoolAccount: { + balance: '1', + __typename: 'AccountBalance', + }, + takerFeeRewardAccount: null, + makerFeeRewardAccount: null, + lpFeeRewardAccount: null, + marketProposerRewardAccount: null, + __typename: 'Asset', + }, + __typename: 'AccountBalance', + }; + + const account2: Account = { + type: Types.AccountType.ACCOUNT_TYPE_GENERAL, + balance: '199994240', + market: null, + asset: { + id: 'assetId-2', + name: 'tUSDC TEST', + symbol: 'tUSDC', + decimals: 5, + quantum: '1', + source: { + __typename: 'ERC20', + contractAddress: '0xdBa6373d0DAAAA44bfAd663Ff93B1bF34cE054E9', + lifetimeLimit: '0', + withdrawThreshold: '0', + }, + status: Types.AssetStatus.STATUS_ENABLED, + infrastructureFeeAccount: { + balance: '2', + __typename: 'AccountBalance', + }, + globalRewardPoolAccount: { + balance: '0', + __typename: 'AccountBalance', + }, + takerFeeRewardAccount: null, + makerFeeRewardAccount: null, + lpFeeRewardAccount: null, + marketProposerRewardAccount: null, + __typename: 'Asset', + }, + __typename: 'AccountBalance', + }; + + beforeEach(() => { + (useWeb3React as jest.Mock).mockReturnValue({ account: MOCK_ETH_ADDRESS }); + }); + afterEach(() => { + jest.resetAllMocks(); + }); + it('should be properly rendered', () => { + mockData = [ + { ...account1 }, + { ...account2 }, + { + type: Types.AccountType.ACCOUNT_TYPE_MARGIN, + balance: '201159', + market: { + __typename: 'Market', + id: 'marketId-1', + decimalPlaces: 5, + positionDecimalPlaces: 0, + state: Types.MarketState.STATE_SUSPENDED, + tradingMode: Types.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION, + fees: { + __typename: 'Fees', + factors: { + __typename: 'FeeFactors', + makerFee: '0.0002', + infrastructureFee: '0.0005', + liquidityFee: '0.001', + }, + }, + tradableInstrument: { + __typename: 'TradableInstrument', + instrument: { + __typename: 'Instrument', + id: '', + name: 'Apple Monthly (Nov 2022)', + code: 'AAPL.MF21', + metadata: { + __typename: 'InstrumentMetadata', + tags: [ + 'formerly:4899E01009F1A721', + 'quote:USD', + 'ticker:AAPL', + 'class:equities/single-stock-futures', + 'sector:tech', + 'listing_venue:NASDAQ', + 'country:US', + 'auto:aapl', + ], + }, + product: { + __typename: 'Future', + settlementAsset: { + __typename: 'Asset', + symbol: 'tUSDC', + decimals: 5, + }, + quoteName: 'USD', + }, + }, + }, + marketTimestamps: { + __typename: 'MarketTimestamps', + open: '2022-10-25T18:17:59.149283671Z', + close: null, + }, + }, + asset: { + id: 'assetId-2', + name: 'tUSDC TEST', + symbol: 'tUSDC', + decimals: 5, + quantum: '1', + source: { + __typename: 'ERC20', + contractAddress: '0xdBa6373d0DAAAA44bfAd663Ff93B1bF34cE054E9', + lifetimeLimit: '0', + withdrawThreshold: '0', + }, + status: Types.AssetStatus.STATUS_ENABLED, + infrastructureFeeAccount: { + balance: '2', + __typename: 'AccountBalance', + }, + globalRewardPoolAccount: { + balance: '0', + __typename: 'AccountBalance', + }, + takerFeeRewardAccount: null, + makerFeeRewardAccount: null, + lpFeeRewardAccount: null, + marketProposerRewardAccount: null, + __typename: 'Asset', + }, + __typename: 'AccountBalance', + }, + ]; + render( + + + + ); + expect(screen.getByTestId('select-asset')).toBeInTheDocument(); + expect(screen.getAllByRole('option')).toHaveLength(3); + }); + + it('should display no data message', () => { + mockData = null; + render( + + + + ); + expect( + screen.getByText('You have no assets to withdraw') + ).toBeInTheDocument(); + }); + + it('should filter out zero balance account assets', () => { + mockData = [{ ...account1 }, { ...account2, balance: '0' }]; + render( + + + + ); + expect(screen.getByTestId('select-asset')).toBeInTheDocument(); + expect(screen.getAllByRole('option')).toHaveLength(2); + }); + + it('when no accounts have a balance should should display no data message', () => { + mockData = [ + { ...account1, balance: '0' }, + { ...account2, balance: '0' }, + ]; + render( + + + + ); + expect( + screen.getByText('You have no assets to withdraw') + ).toBeInTheDocument(); + }); +}); diff --git a/libs/withdraws/src/lib/withdraw-form-container.tsx b/libs/withdraws/src/lib/withdraw-form-container.tsx index 339665076..f7bc7586c 100644 --- a/libs/withdraws/src/lib/withdraw-form-container.tsx +++ b/libs/withdraws/src/lib/withdraw-form-container.tsx @@ -1,11 +1,10 @@ -import { useDataProvider } from '@vegaprotocol/react-helpers'; +import { useMemo } from 'react'; +import { useDataProvider, t, toBigNum } from '@vegaprotocol/react-helpers'; import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; -import { enabledAssetsProvider } from '@vegaprotocol/assets'; -import { accountsOnlyDataProvider } from '@vegaprotocol/accounts'; +import { accountsDataProvider } from '@vegaprotocol/accounts'; import type { WithdrawalArgs } from './use-create-withdraw'; import { WithdrawManager } from './withdraw-manager'; -import { useMemo } from 'react'; -import { t } from '@vegaprotocol/react-helpers'; +import { Schema as Types } from '@vegaprotocol/types'; interface WithdrawFormContainerProps { partyId?: string; @@ -20,24 +19,23 @@ export const WithdrawFormContainer = ({ }: WithdrawFormContainerProps) => { const variables = useMemo(() => ({ partyId }), [partyId]); const { data, loading, error } = useDataProvider({ - dataProvider: accountsOnlyDataProvider, + dataProvider: accountsDataProvider, variables, - noUpdate: true, - }); - - const { - data: assets, - loading: assetsLoading, - error: assetsError, - } = useDataProvider({ - dataProvider: enabledAssetsProvider, }); + const filteredAsset = data + ?.filter( + (account) => + account.type === Types.AccountType.ACCOUNT_TYPE_GENERAL && + toBigNum(account.balance, account.asset.decimals).isGreaterThan(0) + ) + .map((account) => account.asset); + const assets = filteredAsset?.length ? filteredAsset : null; return ( {assets && data && (