From 551650a68c1bd483aa030649d375c0d06d8348e4 Mon Sep 17 00:00:00 2001 From: Douglas Daniel Date: Thu, 11 May 2023 15:46:50 -0500 Subject: [PATCH] fix(wallet): Removing Auto Discovered Tokens --- .../common/actions/wallet_actions.ts | 10 +- .../brave_wallet_ui/common/async/lib.ts | 27 ++-- .../common/constants/local-storage-keys.ts | 6 +- .../common/hooks/assets-management.ts | 131 +++++++++++++++--- .../common/selectors/wallet-selectors.ts | 4 + .../common/slices/wallet.slice.ts | 36 ++++- .../desktop/asset-watchlist-item/index.tsx | 20 +-- .../edit-visible-assets-modal/index.tsx | 130 +++++++++-------- .../virtualized-visible-assets-list.tsx | 16 ++- .../views/portfolio/portfolio-asset.tsx | 11 +- components/brave_wallet_ui/constants/types.ts | 4 +- .../stories/mock-data/mock-wallet-state.ts | 4 +- .../brave_wallet_ui/utils/asset-utils.ts | 2 +- 13 files changed, 282 insertions(+), 119 deletions(-) diff --git a/components/brave_wallet_ui/common/actions/wallet_actions.ts b/components/brave_wallet_ui/common/actions/wallet_actions.ts index d812e46d9e65..543741eb9515 100644 --- a/components/brave_wallet_ui/common/actions/wallet_actions.ts +++ b/components/brave_wallet_ui/common/actions/wallet_actions.ts @@ -3,10 +3,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at https://mozilla.org/MPL/2.0/. */ - import { WalletActions } from '../slices/wallet.slice' +import { WalletActions } from '../slices/wallet.slice' - // We must re-export actions here until we remove all imports of this file - export const { +// We must re-export actions here until we remove all imports of this file +export const { accountsChanged, activeOriginChanged, addAccount, @@ -98,5 +98,7 @@ updateUnapprovedTransactionSpendAllowance, updateUserAsset, setHidePortfolioGraph, - setHidePortfolioBalances + setHidePortfolioBalances, + setRemovedFungibleTokenIds, + setRemovedNonFungibleTokenIds } = WalletActions diff --git a/components/brave_wallet_ui/common/async/lib.ts b/components/brave_wallet_ui/common/async/lib.ts index bdecccdbcc66..8c51205cc654 100644 --- a/components/brave_wallet_ui/common/async/lib.ts +++ b/components/brave_wallet_ui/common/async/lib.ts @@ -34,7 +34,7 @@ import { import { getTokenParam, getFlattenedAccountBalances } from '../../utils/api-utils' import Amount from '../../utils/amount' import { sortTransactionByDate } from '../../utils/tx-utils' -import { getBatTokensFromList, getNativeTokensFromList, getUniqueAssets } from '../../utils/asset-utils' +import { getAssetIdKey, getBatTokensFromList, getNativeTokensFromList, getUniqueAssets } from '../../utils/asset-utils' import { loadTimeData } from '../../../common/loadTimeData' import { getVisibleNetworksList } from '../slices/api.slice' @@ -62,7 +62,7 @@ export const getERC20Allowance = ( const { braveWalletService, jsonRpcService } = getAPIProxy() const { chainId } = await braveWalletService.getChainIdForActiveOrigin( - BraveWallet.CoinType.ETH) + BraveWallet.CoinType.ETH) const result = await jsonRpcService.getERC20TokenAllowance( contractAddress, ownerAddress, @@ -488,8 +488,14 @@ export function refreshVisibleTokenInfo (targetNetwork?: BraveWallet.NetworkInfo const visibleAssets = targetNetwork ? await inner(targetNetwork) : await Promise.all(networkList.map(async (item) => await inner(item))) - - const userVisibleTokensInfo = visibleAssets.flat(1) + const removedAssetIds = + [ + ...getState().wallet.removedFungibleTokenIds, + ...getState().wallet.removedNonFungibleTokenIds + ] + const userVisibleTokensInfo = visibleAssets + .flat(1) + .filter(token => !removedAssetIds.includes(getAssetIdKey(token))) await dispatch(WalletActions.setVisibleTokensInfo(userVisibleTokensInfo)) const nfts = userVisibleTokensInfo.filter((asset) => asset.isErc721 || asset.isNft) dispatch(WalletPageActions.getNftsPinningStatus(nfts)) @@ -497,8 +503,8 @@ export function refreshVisibleTokenInfo (targetNetwork?: BraveWallet.NetworkInfo } function reportActiveWalletsToP3A (accounts: WalletAccountType[], - nativeBalances: BalancePayload[][], - blockchainTokenBalances: BalancePayload[][]) { + nativeBalances: BalancePayload[][], + blockchainTokenBalances: BalancePayload[][]) { const { braveWalletP3A } = getAPIProxy() const coinsActiveAddresses: { [coin: BraveWallet.CoinType]: { @@ -632,7 +638,12 @@ export function refreshBalances () { await jsonRpcService.getERC721TokenBalance(token.contractAddress, token.tokenId ?? '', account.address, token?.chainId ?? '') } else { balanceInfo = - await jsonRpcService.getERC20TokenBalance(token.contractAddress, account.address, token?.chainId ?? '') + await jsonRpcService + .getERC20TokenBalance( + token.contractAddress, + account.address, + token?.chainId ?? '' + ) } } return { @@ -1125,7 +1136,7 @@ export const areSupportedForPinning = async (urls: string[]) => { export const extractIpfsUrl = async (url: string | undefined) => { const { braveWalletIpfsService } = getAPIProxy() const trimmedUrl = url ? url.trim() : '' - if (isIpfs(trimmedUrl)) { + if (isIpfs(trimmedUrl)) { return trimmedUrl } return (await braveWalletIpfsService diff --git a/components/brave_wallet_ui/common/constants/local-storage-keys.ts b/components/brave_wallet_ui/common/constants/local-storage-keys.ts index 24740a3ade99..f551672735e7 100644 --- a/components/brave_wallet_ui/common/constants/local-storage-keys.ts +++ b/components/brave_wallet_ui/common/constants/local-storage-keys.ts @@ -11,5 +11,9 @@ export const LOCAL_STORAGE_KEYS = { PORTFOLIO_ASSET_FILTER_OPTION: 'PORTFOLIO_ASSET_FILTER_OPTION', PORTFOLIO_TIME_LINE_OPTION: 'PORTFOLIO_TIME_LINE_OPTION', IS_IPFS_BANNER_HIDDEN: 'BRAVE_WALLET_IS_IPFS_BANNER_HIDDEN', - IS_ENABLE_NFT_AUTO_DISCOVERY_MODAL_HIDDEN: 'BRAVE_WALLET_IS_ENABLE_NFT_AUTO_DISCOVERY_MODAL_HIDDEN' + IS_ENABLE_NFT_AUTO_DISCOVERY_MODAL_HIDDEN: 'BRAVE_WALLET_IS_ENABLE_NFT_AUTO_DISCOVERY_MODAL_HIDDEN', + USER_REMOVED_NON_FUNGIBLE_TOKEN_IDS: + 'BRAVE_WALLET_USER_REMOVED_NON_FUNGIBLE_TOKEN_IDS', + USER_REMOVED_FUNGIBLE_TOKEN_IDS: + 'BRAVE_WALLET_USER_REMOVED_FUNGIBLE_TOKEN_IDS' } as const diff --git a/components/brave_wallet_ui/common/hooks/assets-management.ts b/components/brave_wallet_ui/common/hooks/assets-management.ts index aee1cc21430c..2b87e13522e4 100644 --- a/components/brave_wallet_ui/common/hooks/assets-management.ts +++ b/components/brave_wallet_ui/common/hooks/assets-management.ts @@ -4,14 +4,22 @@ // you can obtain one at https://mozilla.org/MPL/2.0/. import * as React from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' + +// Selectors +import { + useUnsafeWalletSelector +} from './use-safe-selector' +import { WalletSelectors } from '../selectors' // Constants -import { BraveWallet, WalletState } from '../../constants/types' +import { BraveWallet } from '../../constants/types' // Utils import { stripERC20TokenImageURL } from '../../utils/string-utils' import { WalletActions } from '../actions' +import { LOCAL_STORAGE_KEYS } from '../constants/local-storage-keys' +import { getAssetIdKey } from '../../utils/asset-utils' const onlyInLeft = (left: BraveWallet.BlockchainToken[], right: BraveWallet.BlockchainToken[]) => left.filter(leftValue => @@ -28,27 +36,101 @@ const findTokensWithMismatchedVisibility = (left: BraveWallet.BlockchainToken[], leftValue.visible !== rightValue.visible)) export default function useAssetManagement () { - // redux - const { - userVisibleTokensInfo - } = useSelector(({ wallet }: { wallet: WalletState }) => wallet) - const dispatch = useDispatch() + // selectors + const userVisibleTokensInfo = + useUnsafeWalletSelector(WalletSelectors.userVisibleTokensInfo) + const removedFungibleTokenIds = + useUnsafeWalletSelector(WalletSelectors.removedFungibleTokenIds) + const removedNonFungibleTokenIds = + useUnsafeWalletSelector(WalletSelectors.removedNonFungibleTokenIds) - const onAddUserAsset = (token: BraveWallet.BlockchainToken) => { - dispatch(WalletActions.addUserAsset({ - ...token, - logo: stripERC20TokenImageURL(token.logo) || '' - })) - } - const onAddCustomAsset = (token: BraveWallet.BlockchainToken) => { - onAddUserAsset(token) + // redux + const dispatch = useDispatch() - // We handle refreshing balances for ERC721 tokens in the addUserAsset handler. - if (!(token.isErc721 || token.isNft)) { - dispatch(WalletActions.refreshBalancesAndPriceHistory()) - } - } + const tokenIsSetAsRemovedInLocalStorage = React.useCallback( + ( + token: BraveWallet.BlockchainToken + ) => { + const assetId = getAssetIdKey(token) + return token.isNft || + token.isErc1155 || + token.isErc721 + ? removedNonFungibleTokenIds.includes(assetId) + : removedFungibleTokenIds.includes(assetId) + }, [removedNonFungibleTokenIds, removedFungibleTokenIds]) + + const addOrRemoveTokenInLocalStorage = React.useCallback( + ( + token: BraveWallet.BlockchainToken, + addOrRemove: 'add' | 'remove' + ) => { + const assetId = getAssetIdKey(token) + const isNFT = token.isNft || token.isErc1155 || token.isErc721 + const removedList = isNFT + ? removedNonFungibleTokenIds + : removedFungibleTokenIds + const localStorageKey = isNFT + ? LOCAL_STORAGE_KEYS.USER_REMOVED_NON_FUNGIBLE_TOKEN_IDS + : LOCAL_STORAGE_KEYS.USER_REMOVED_FUNGIBLE_TOKEN_IDS + + // add assetId if it is not in the array + if (addOrRemove === 'remove') { + const newList = [...removedList, assetId] + // update state + if (isNFT) { + dispatch(WalletActions.setRemovedNonFungibleTokenIds(newList)) + } else { + dispatch(WalletActions.setRemovedFungibleTokenIds(newList)) + } + // persist array + localStorage.setItem(localStorageKey, JSON.stringify(newList)) + } + + // add assetId if it is not in the array + if (addOrRemove === 'add') { + const newList = removedList.filter((id) => id !== assetId) + // update state + if (isNFT) { + dispatch(WalletActions.setRemovedNonFungibleTokenIds(newList)) + } else { + dispatch(WalletActions.setRemovedFungibleTokenIds(newList)) + } + // persist array + localStorage.setItem(localStorageKey, JSON.stringify(newList)) + } + + }, [removedNonFungibleTokenIds, removedFungibleTokenIds]) + + const onAddUserAsset = React.useCallback( + ( + token: BraveWallet.BlockchainToken + ) => { + if (tokenIsSetAsRemovedInLocalStorage(token)) { + addOrRemoveTokenInLocalStorage(token, 'add') + } else { + dispatch(WalletActions.addUserAsset({ + ...token, + logo: stripERC20TokenImageURL(token.logo) || '' + })) + } + }, [ + addOrRemoveTokenInLocalStorage, + tokenIsSetAsRemovedInLocalStorage + ]) + + const onAddCustomAsset = React.useCallback( + ( + token: BraveWallet.BlockchainToken + ) => { + onAddUserAsset(token) + + // We handle refreshing balances for ERC721 tokens in the + // addUserAsset handler. + if (!(token.isErc721 || token.isNft)) { + dispatch(WalletActions.refreshBalancesAndPriceHistory()) + } + }, [onAddUserAsset]) const onUpdateVisibleAssets = React.useCallback((updatedTokensList: BraveWallet.BlockchainToken[]) => { // Gets a list of all added tokens and adds them to the userVisibleTokensInfo list @@ -57,7 +139,12 @@ export default function useAssetManagement () { // Gets a list of all removed tokens and removes them from the userVisibleTokensInfo list onlyInLeft(userVisibleTokensInfo, updatedTokensList) - .forEach(token => dispatch(WalletActions.removeUserAsset(token))) + .forEach(token => { + dispatch(WalletActions.removeUserAsset(token)) + if (!tokenIsSetAsRemovedInLocalStorage(token)) { + addOrRemoveTokenInLocalStorage(token, 'remove') + } + }) // Gets a list of custom tokens and native assets returned from updatedTokensList payload // then compares against userVisibleTokensInfo list and updates the tokens visibility if it has changed. @@ -66,7 +153,7 @@ export default function useAssetManagement () { // Refresh Balances, Prices and Price History when done. dispatch(WalletActions.refreshBalancesAndPriceHistory()) - }, [userVisibleTokensInfo]) + }, [userVisibleTokensInfo, addOrRemoveTokenInLocalStorage]) const makeTokenVisible = React.useCallback((token: BraveWallet.BlockchainToken) => { const foundTokenIdx = userVisibleTokensInfo.findIndex(t => diff --git a/components/brave_wallet_ui/common/selectors/wallet-selectors.ts b/components/brave_wallet_ui/common/selectors/wallet-selectors.ts index 6919bacb2136..cb1b004ab204 100644 --- a/components/brave_wallet_ui/common/selectors/wallet-selectors.ts +++ b/components/brave_wallet_ui/common/selectors/wallet-selectors.ts @@ -59,3 +59,7 @@ export const transactionSpotPrices = ({ wallet }: State) => wallet.transactionSp export const transactions = ({ wallet }: State) => wallet.transactions export const userVisibleTokensInfo = ({ wallet }: State) => wallet.userVisibleTokensInfo export const selectedAccountFilter = ({ wallet }: State) => wallet.selectedAccountFilter +export const removedFungibleTokenIds = ({ wallet }: State) => + wallet.removedFungibleTokenIds +export const removedNonFungibleTokenIds = ({ wallet }: State) => + wallet.removedNonFungibleTokenIds diff --git a/components/brave_wallet_ui/common/slices/wallet.slice.ts b/components/brave_wallet_ui/common/slices/wallet.slice.ts index 6ea14ae068d9..f34857340853 100644 --- a/components/brave_wallet_ui/common/slices/wallet.slice.ts +++ b/components/brave_wallet_ui/common/slices/wallet.slice.ts @@ -157,6 +157,20 @@ const defaultState: WalletState = { LOCAL_STORAGE_KEYS .HIDE_PORTFOLIO_BALANCES ) === 'true', + removedFungibleTokenIds: + JSON.parse( + localStorage + .getItem( + LOCAL_STORAGE_KEYS + .USER_REMOVED_FUNGIBLE_TOKEN_IDS + ) || '[]'), + removedNonFungibleTokenIds: + JSON.parse( + localStorage + .getItem( + LOCAL_STORAGE_KEYS + .USER_REMOVED_NON_FUNGIBLE_TOKEN_IDS + ) || '[]') } // async actions @@ -428,9 +442,9 @@ export const createWalletSlice = (initialState: WalletState = defaultState) => { setCoinMarkets (state: WalletState, { payload }: PayloadAction) { state.coinMarketData = payload.success ? payload.values.map(coin => { - coin.image = coin.image.replace('https://assets.coingecko.com', ' https://assets.cgproxy.brave.com') - return coin - }) + coin.image = coin.image.replace('https://assets.coingecko.com', ' https://assets.cgproxy.brave.com') + return coin + }) : [] state.isLoadingCoinMarketData = false }, @@ -477,6 +491,22 @@ export const createWalletSlice = (initialState: WalletState = defaultState) => { state.hidePortfolioGraph = payload }, + setRemovedFungibleTokenIds + ( + state: WalletState, + { payload }: PayloadAction + ) { + state.removedFungibleTokenIds = payload + }, + + setRemovedNonFungibleTokenIds + ( + state: WalletState, + { payload }: PayloadAction + ) { + state.removedNonFungibleTokenIds = payload + }, + setHidePortfolioBalances ( state: WalletState, diff --git a/components/brave_wallet_ui/components/desktop/asset-watchlist-item/index.tsx b/components/brave_wallet_ui/components/desktop/asset-watchlist-item/index.tsx index 561122d6a8d3..aa0f0d904fc1 100644 --- a/components/brave_wallet_ui/components/desktop/asset-watchlist-item/index.tsx +++ b/components/brave_wallet_ui/components/desktop/asset-watchlist-item/index.tsx @@ -32,9 +32,13 @@ import { } from './style' export interface Props { - onSelectAsset: (key: string, selected: boolean, token: BraveWallet.BlockchainToken, isCustom: boolean) => void + onSelectAsset: ( + key: string, + selected: boolean, + token: BraveWallet.BlockchainToken + ) => void onRemoveAsset: (token: BraveWallet.BlockchainToken) => void - isCustom: boolean + isRemovable: boolean isSelected: boolean token: BraveWallet.BlockchainToken } @@ -44,7 +48,7 @@ const AssetWatchlistItem = React.forwardRef( const { onSelectAsset, onRemoveAsset, - isCustom, + isRemovable, token, isSelected } = props @@ -54,12 +58,12 @@ const AssetWatchlistItem = React.forwardRef( // callbacks const onCheck = React.useCallback((key: string, selected: boolean) => { - onSelectAsset(key, selected, token, isCustom) - }, [onSelectAsset, token, isCustom]) + onSelectAsset(key, selected, token) + }, [onSelectAsset, token]) const onClickAsset = React.useCallback(() => { - onSelectAsset(token.contractAddress, !isSelected, token, isCustom) - }, [onSelectAsset, token, isSelected, isCustom]) + onSelectAsset(token.contractAddress, !isSelected, token) + }, [onSelectAsset, token, isSelected]) const onClickRemoveAsset = React.useCallback(() => { onRemoveAsset(token) @@ -91,7 +95,7 @@ const AssetWatchlistItem = React.forwardRef( - {isCustom && + {isRemovable && diff --git a/components/brave_wallet_ui/components/desktop/popup-modals/edit-visible-assets-modal/index.tsx b/components/brave_wallet_ui/components/desktop/popup-modals/edit-visible-assets-modal/index.tsx index c9978c29584a..bd38b4cb4b38 100644 --- a/components/brave_wallet_ui/components/desktop/popup-modals/edit-visible-assets-modal/index.tsx +++ b/components/brave_wallet_ui/components/desktop/popup-modals/edit-visible-assets-modal/index.tsx @@ -117,13 +117,37 @@ const EditVisibleAssetsModal = ({ onClose }: Props) => { return Object.keys(tokenRegistry).length === 0 ? [] : tokenRegistry[selectedNetworkFilter.chainId] }, [tokenRegistry, selectedNetworkFilter.chainId, fullTokenListAllChains, Object.keys(tokenRegistry).length]) + // User tokens sorted by visibility + const usersTokensSortedByVisibility + : BraveWallet.BlockchainToken[] = + React.useMemo(() => { + return [...userVisibleTokensInfo] + .sort((a, b) => + Number(b.visible) - Number(a.visible) + ) + }, [userVisibleTokensInfo]) + // Users visible tokens based on selectedNetworkFilter - const userVisibleTokensBySelectedNetwork: BraveWallet.BlockchainToken[] = React.useMemo(() => { - if (selectedNetworkFilter.chainId === AllNetworksOption.chainId) { - return userVisibleTokensInfo - } - return userVisibleTokensInfo.filter((token) => token.chainId === selectedNetworkFilter.chainId) - }, [userVisibleTokensInfo, selectedNetworkFilter.chainId, tokenRegistry]) + const userVisibleTokensBySelectedNetwork + : BraveWallet.BlockchainToken[] = + React.useMemo(() => { + if ( + selectedNetworkFilter.chainId === + AllNetworksOption.chainId + ) { + return usersTokensSortedByVisibility + } + return usersTokensSortedByVisibility + .filter( + (token) => + token.chainId === + selectedNetworkFilter.chainId + ) + }, [ + usersTokensSortedByVisibility, + selectedNetworkFilter.chainId, + tokenRegistry + ]) // Constructed list based on Users Visible Tokens and Full Token List const tokenList: BraveWallet.BlockchainToken[] = React.useMemo(() => { @@ -141,7 +165,13 @@ const EditVisibleAssetsModal = ({ onClose }: Props) => { return isUserVisibleTokensInfoEmpty ? filteredTokenRegistry : [...userVisibleTokensBySelectedNetwork, ...filteredTokenRegistry] - }, [isUserVisibleTokensInfoEmpty, selectedNetworkList, userVisibleTokensInfo, nativeAsset]) + }, [ + isUserVisibleTokensInfoEmpty, + selectedNetworkList, + userVisibleTokensInfo, + nativeAsset, + userVisibleTokensBySelectedNetwork + ]) // Filtered token list based on user removed tokens const filteredOutRemovedTokens = React.useMemo(() => { @@ -184,58 +214,50 @@ const EditVisibleAssetsModal = ({ onClose }: Props) => { return (isUserToken(token) && findUpdatedTokenInfo(token)?.visible) ?? false }, [isUserToken, findUpdatedTokenInfo]) - const isCustomToken = React.useCallback((token: BraveWallet.BlockchainToken): boolean => { - if (token.contractAddress === '') { - return false - } - - // Any token with a tokenId should be considered a custom token. - if (token.tokenId !== '') { - return true - } - - return !fullTokenListAllChains - .some(each => each.contractAddress.toLowerCase() === token.contractAddress.toLowerCase()) - }, [fullTokenListAllChains]) - - const addOrRemoveTokenFromList = React.useCallback((selected: boolean, token: BraveWallet.BlockchainToken) => { - if (selected) { - return [...updatedTokensList, token] - } - return updatedTokensList.filter((t) => t !== token) - }, [updatedTokensList]) + const isRemovable = React.useCallback( + ( + token: BraveWallet.BlockchainToken + ): boolean => { + // Native assets should not be removable. + if (token.contractAddress === '') { + return false + } - // Do to a bug, users were able to set a non custom token's - // visibility to false. We only allow setting visibility to custom tokens - // to make it easier for users to re-add in the future. This method is added - // to help the user get un-stuck. - const findNonCustomTokenWithVisibleFalse = React.useCallback((token: BraveWallet.BlockchainToken) => { - return userVisibleTokensInfo.some((t) => - checkIfTokensMatch(t, token) && - !t.visible) - }, [userVisibleTokensInfo]) + // Any NFT should be removable. + if ( + token.isErc721 || + token.isErc1155 || + token.isNft + ) { + return true + } - const onCheckWatchlistItem = React.useCallback((key: string, selected: boolean, token: BraveWallet.BlockchainToken, isCustom: boolean) => { - if (isUserToken(token)) { - if (isCustom || token.contractAddress === '' || (!isCustom && findNonCustomTokenWithVisibleFalse(token))) { - const updatedToken = selected ? { ...token, visible: true } : { ...token, visible: false } - const tokenIndex = updatedTokensList.findIndex((t) => checkIfTokensMatch(t, token)) + return !fullTokenListAllChains + .some( + each => + each.contractAddress.toLowerCase() === + token.contractAddress.toLowerCase() + ) + }, [fullTokenListAllChains]) + + const onCheckWatchlistItem = React.useCallback( + ( + key: string, + selected: boolean, + token: BraveWallet.BlockchainToken + ) => { + if (isUserToken(token)) { + const updatedToken = { ...token, visible: selected } + const tokenIndex = + updatedTokensList + .findIndex((t) => checkIfTokensMatch(t, token)) let newList = [...updatedTokensList] newList.splice(tokenIndex, 1, updatedToken) setUpdatedTokensList(newList) - } else { - if (token.isErc721) setTokenContractAddress(token.contractAddress) - setUpdatedTokensList(addOrRemoveTokenFromList(selected, token)) + return } - return - } - if (token.isErc721 || token.isNft) { - setShowAddCustomToken(true) - setTokenContractAddress(token.contractAddress) - return - } - setUpdatedTokensList(addOrRemoveTokenFromList(selected, token)) - }, [isUserToken, updatedTokensList, addOrRemoveTokenFromList, findNonCustomTokenWithVisibleFalse]) + setUpdatedTokensList([...updatedTokensList, token]) + }, [isUserToken, updatedTokensList]) const toggleShowAddCustomToken = () => setShowAddCustomToken(prev => !prev) @@ -314,7 +336,7 @@ const EditVisibleAssetsModal = ({ onClose }: Props) => { : boolean + isRemovable: (token: BraveWallet.BlockchainToken) => boolean onRemoveAsset: (token: BraveWallet.BlockchainToken) => void isAssetSelected: (token: BraveWallet.BlockchainToken) => boolean - onCheckWatchlistItem: (key: string, selected: boolean, token: BraveWallet.BlockchainToken, isCustom: boolean) => void + onCheckWatchlistItem: ( + key: string, + selected: boolean, + token: BraveWallet.BlockchainToken + ) => void } interface ListItemProps extends Omit { @@ -42,7 +46,7 @@ const ListItem = (props: ListItemProps) => { data, style, index, - isCustomToken, + isRemovable, isAssetSelected, onCheckWatchlistItem, onRemoveAsset, @@ -59,7 +63,7 @@ const ListItem = (props: ListItemProps) => {
{ export const VirtualizedVisibleAssetsList = (props: VirtualizedTokensListProps) => { const { tokenList, - isCustomToken, + isRemovable, isAssetSelected, onCheckWatchlistItem, onRemoveAsset @@ -109,7 +113,7 @@ export const VirtualizedVisibleAssetsList = (props: VirtualizedTokensListProps) children={({ data, index, style }) => ( { const onHideAsset = React.useCallback(() => { if (!selectedAsset) return - if ( - fullTokenList.some((asset) => - asset.contractAddress.toLowerCase() === - selectedAsset.contractAddress.toLowerCase()) - ) { - dispatch(WalletActions.removeUserAsset(selectedAsset)) - } else { - dispatch(WalletActions.setUserAssetVisible({ token: selectedAsset, isVisible: false })) - } dispatch(WalletActions.setUserAssetVisible({ token: selectedAsset, isVisible: false })) dispatch(WalletActions.refreshBalancesAndPriceHistory()) dispatch(WalletPageActions.selectAsset({ @@ -505,7 +496,7 @@ export const PortfolioAsset = (props: Props) => { if (showHideTokenModel) setShowHideTokenModal(false) if (showTokenDetailsModal) setShowTokenDetailsModal(false) history.push(WalletRoutes.PortfolioAssets) - }, [selectedAsset, showTokenDetailsModal, fullTokenList]) + }, [selectedAsset, showTokenDetailsModal]) const onCloseNftModal = React.useCallback(() => { setshowNftModal(false) diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index 1551eb5e1f26..ef0e49c1af23 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -278,7 +278,9 @@ export interface WalletState { isNftPinningFeatureEnabled: boolean isPanelV2FeatureEnabled: boolean hidePortfolioGraph: boolean - hidePortfolioBalances: boolean + hidePortfolioBalances: boolean, + removedFungibleTokenIds: string[] + removedNonFungibleTokenIds: string[] } export interface PanelState { diff --git a/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts b/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts index 98a902673a8a..5b2ff4717c23 100644 --- a/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts +++ b/components/brave_wallet_ui/stories/mock-data/mock-wallet-state.ts @@ -313,5 +313,7 @@ export const mockWalletState: WalletState = { isNftPinningFeatureEnabled: false, isPanelV2FeatureEnabled: false, hidePortfolioBalances: false, - hidePortfolioGraph: false + hidePortfolioGraph: false, + removedFungibleTokenIds: [], + removedNonFungibleTokenIds: [] } diff --git a/components/brave_wallet_ui/utils/asset-utils.ts b/components/brave_wallet_ui/utils/asset-utils.ts index e578878250db..16875c51d513 100644 --- a/components/brave_wallet_ui/utils/asset-utils.ts +++ b/components/brave_wallet_ui/utils/asset-utils.ts @@ -165,7 +165,7 @@ export type GetBlockchainTokenIdArg = Pick< * @returns an id that can be used as a react element key */ export const getAssetIdKey = (asset: GetBlockchainTokenIdArg) => { - return asset.isErc721 + return asset.tokenId ? `${asset.contractAddress}-${asset.tokenId}-${asset.chainId}` : `${asset.contractAddress}-${asset.chainId}` }