Skip to content

Commit

Permalink
fix: prevent selecting chain if asset would become unsupported (#8502)
Browse files Browse the repository at this point in the history
* fix: prevent selecting chain if asset would become unsupported

* fix: linting
  • Loading branch information
woodenfurniture authored Jan 8, 2025
1 parent b476005 commit a18c817
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 31 deletions.
5 changes: 5 additions & 0 deletions src/components/AssetSelection/AssetSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type TradeAssetSelectBaseProps = {
isLoading?: boolean
buttonProps?: ButtonProps
onlyConnectedChains: boolean
assetFilterPredicate?: (assetId: AssetId) => boolean
chainIdFilterPredicate?: (chainId: ChainId) => boolean
} & FlexProps

Expand Down Expand Up @@ -44,6 +45,7 @@ export const TradeAssetSelect: React.FC<TradeAssetSelectProps> = memo(props => {
isLoading,
onlyConnectedChains,
buttonProps,
assetFilterPredicate,
chainIdFilterPredicate,
flexProps,
} = useMemo(() => {
Expand All @@ -56,6 +58,7 @@ export const TradeAssetSelect: React.FC<TradeAssetSelectProps> = memo(props => {
isLoading,
onlyConnectedChains,
buttonProps,
assetFilterPredicate,
chainIdFilterPredicate,
...flexProps
} = props
Expand All @@ -68,6 +71,7 @@ export const TradeAssetSelect: React.FC<TradeAssetSelectProps> = memo(props => {
isLoading,
onlyConnectedChains,
buttonProps,
assetFilterPredicate,
chainIdFilterPredicate,
flexProps,
}
Expand Down Expand Up @@ -109,6 +113,7 @@ export const TradeAssetSelect: React.FC<TradeAssetSelectProps> = memo(props => {
rightIcon={rightIcon}
onlyConnectedChains={onlyConnectedChains}
chainIdFilterPredicate={chainIdFilterPredicate}
assetFilterPredicate={assetFilterPredicate}
/>
</Flex>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type AssetChainDropdownProps = {
isError?: boolean
onlyConnectedChains: boolean
isDisabled?: boolean
assetFilterPredicate?: (assetId: AssetId) => boolean
chainIdFilterPredicate?: (chainId: ChainId) => boolean
}

Expand All @@ -48,6 +49,7 @@ export const AssetChainDropdown: React.FC<AssetChainDropdownProps> = memo(
isLoading,
onChangeAsset,
onlyConnectedChains,
assetFilterPredicate,
chainIdFilterPredicate,
}) => {
const {
Expand All @@ -68,11 +70,13 @@ export const AssetChainDropdown: React.FC<AssetChainDropdownProps> = memo(
const filteredRelatedAssetIds = useMemo(() => {
const filteredRelatedAssetIds = relatedAssetIds.filter(assetId => {
const { chainId } = fromAssetId(assetId)
return chainIdFilterPredicate?.(chainId) ?? true
const isChainAllowed = chainIdFilterPredicate?.(chainId) ?? true
const isAssetAllowed = assetFilterPredicate?.(assetId) ?? true
return isChainAllowed && isAssetAllowed
})
if (!assetIds?.length) return filteredRelatedAssetIds
return filteredRelatedAssetIds.filter(relatedAssetId => assetIds.includes(relatedAssetId))
}, [assetIds, chainIdFilterPredicate, relatedAssetIds])
}, [assetFilterPredicate, assetIds, chainIdFilterPredicate, relatedAssetIds])

const renderedChains = useMemo(() => {
if (!assetId) return null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ChainId } from '@shapeshiftoss/caip'
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import type { FC } from 'react'
import { memo, useCallback } from 'react'
Expand All @@ -17,14 +17,14 @@ import { useModal } from 'hooks/useModal/useModal'
export type TradeAssetSearchModalProps = TradeAssetSearchProps & {
title?: string
onAssetClick: Required<TradeAssetSearchProps>['onAssetClick']
assetFilterPredicate: (asset: Asset) => boolean
assetFilterPredicate: (assetId: AssetId) => boolean
chainIdFilterPredicate: (chainId: ChainId) => boolean
}

type AssetSearchModalBaseProps = TradeAssetSearchModalProps & {
isOpen: boolean
close: () => void
assetFilterPredicate: (asset: Asset) => boolean
assetFilterPredicate: (assetId: AssetId) => boolean
chainIdFilterPredicate: (chainId: ChainId) => boolean
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AccountId, ChainId } from '@shapeshiftoss/caip'
import type { AccountId, AssetId, ChainId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import React, { memo, useCallback, useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
Expand Down Expand Up @@ -32,7 +32,7 @@ export type LimitOrderBuyAssetProps = {
asset: Asset
accountId?: AccountId
isInputtingFiatSellAmount: boolean
assetFilterPredicate: (asset: Asset) => boolean
assetFilterPredicate: (assetId: AssetId) => boolean
chainIdFilterPredicate: (chainId: ChainId) => boolean
onAccountIdChange: AccountDropdownProps['onChange']
onSetBuyAsset: (asset: Asset) => void
Expand Down Expand Up @@ -73,10 +73,17 @@ export const LimitOrderBuyAsset: React.FC<LimitOrderBuyAssetProps> = memo(
onAssetClick={handleAssetClick}
onAssetChange={onSetBuyAsset}
onlyConnectedChains={false}
assetFilterPredicate={assetFilterPredicate}
chainIdFilterPredicate={chainIdFilterPredicate}
/>
),
[asset.assetId, handleAssetClick, onSetBuyAsset, chainIdFilterPredicate],
[
asset.assetId,
handleAssetClick,
onSetBuyAsset,
assetFilterPredicate,
chainIdFilterPredicate,
],
)

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Button, Divider, Stack, useMediaQuery } from '@chakra-ui/react'
import { skipToken } from '@reduxjs/toolkit/query'
import type { ChainId } from '@shapeshiftoss/caip'
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import { fromAccountId, fromAssetId } from '@shapeshiftoss/caip'
import { COW_SWAP_VAULT_RELAYER_ADDRESS, getCowNetwork, SwapperName } from '@shapeshiftoss/swapper'
import { isNativeEvmAsset } from '@shapeshiftoss/swapper/dist/swappers/utils/helpers/helpers'
import type { Asset, CowSwapError } from '@shapeshiftoss/types'
import type { CowSwapError } from '@shapeshiftoss/types'
import { BigNumber, bn, bnOrZero } from '@shapeshiftoss/utils'
import type { FormEvent } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
Expand Down Expand Up @@ -163,15 +163,17 @@ export const LimitOrderInput = ({
}, [])

const sellAssetFilterPredicate = useCallback(
(asset: Asset) => {
return chainIdFilterPredicate(asset.chainId) && !isNativeEvmAsset(asset.assetId)
(assetId: AssetId) => {
const { chainId } = fromAssetId(assetId)
return chainIdFilterPredicate(chainId) && !isNativeEvmAsset(assetId)
},
[chainIdFilterPredicate],
)

const buyAssetFilterPredicate = useCallback(
(asset: Asset) => {
return chainIdFilterPredicate(asset.chainId)
(assetId: AssetId) => {
const { chainId } = fromAssetId(assetId)
return chainIdFilterPredicate(chainId)
},
[chainIdFilterPredicate],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
IconButton,
Stack,
} from '@chakra-ui/react'
import type { AccountId, ChainId } from '@shapeshiftoss/caip'
import type { AccountId, AssetId, ChainId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import { useCallback, useEffect, useMemo, useRef } from 'react'
import { useTranslate } from 'react-polyglot'
Expand Down Expand Up @@ -36,7 +36,7 @@ type SharedTradeInputBodyProps = {
sellAmountUserCurrency: string | undefined
sellAsset: Asset
sellAccountId: AccountId | undefined
assetFilterPredicate: (asset: Asset) => boolean
assetFilterPredicate: (assetId: AssetId) => boolean
chainIdFilterPredicate: (chainId: ChainId) => boolean
onSwitchAssets: () => void
onChangeIsInputtingFiatSellAmount: (isInputtingFiatSellAmount: boolean) => void
Expand Down Expand Up @@ -125,10 +125,17 @@ export const SharedTradeInputBody = ({
onAssetClick={handleSellAssetClick}
onAssetChange={setSellAsset}
onlyConnectedChains={true}
assetFilterPredicate={assetFilterPredicate}
chainIdFilterPredicate={chainIdFilterPredicate}
/>
),
[handleSellAssetClick, sellAsset.assetId, setSellAsset, chainIdFilterPredicate],
[
sellAsset.assetId,
handleSellAssetClick,
setSellAsset,
assetFilterPredicate,
chainIdFilterPredicate,
],
)

return (
Expand Down
17 changes: 13 additions & 4 deletions src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ChainId } from '@shapeshiftoss/caip'
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import { fromAssetId } from '@shapeshiftoss/caip'
import { isLedger } from '@shapeshiftoss/hdwallet-ledger'
import { isArbitrumBridgeTradeQuoteOrRate } from '@shapeshiftoss/swapper/dist/swappers/ArbitrumBridgeSwapper/getTradeQuote/getTradeQuote'
import type { ThorTradeQuote } from '@shapeshiftoss/swapper/dist/swappers/ThorchainSwapper/types'
Expand Down Expand Up @@ -324,8 +325,9 @@ export const TradeInput = ({ isCompact, tradeInputRef, onChangeTab }: TradeInput

const isSolanaSwapperEnabled = useFeatureFlag('SolanaSwapper')
const assetFilterPredicate = useCallback(
(asset: Asset) => {
if (asset.chainId === KnownChainIds.SolanaMainnet) return isSolanaSwapperEnabled
(assetId: AssetId) => {
const { chainId } = fromAssetId(assetId)
if (chainId === KnownChainIds.SolanaMainnet) return isSolanaSwapperEnabled

return true
},
Expand Down Expand Up @@ -357,10 +359,17 @@ export const TradeInput = ({ isCompact, tradeInputRef, onChangeTab }: TradeInput
onAssetClick={handleBuyAssetClick}
onAssetChange={setBuyAsset}
onlyConnectedChains={false}
assetFilterPredicate={assetFilterPredicate}
chainIdFilterPredicate={chainIdFilterPredicate}
/>
),
[buyAsset.assetId, handleBuyAssetClick, setBuyAsset, chainIdFilterPredicate],
[
buyAsset.assetId,
handleBuyAssetClick,
setBuyAsset,
assetFilterPredicate,
chainIdFilterPredicate,
],
)

const bodyContent = useMemo(() => {
Expand Down
14 changes: 7 additions & 7 deletions src/components/TradeAssetSearch/TradeAssetSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export type TradeAssetSearchProps = {
onAssetClick?: (asset: Asset) => void
formProps?: BoxProps
allowWalletUnsupportedAssets?: boolean
assetFilterPredicate?: (asset: Asset) => boolean
assetFilterPredicate?: (assetId: AssetId) => boolean
chainIdFilterPredicate?: (chainId: ChainId) => boolean
}
export const TradeAssetSearch: FC<TradeAssetSearchProps> = ({
Expand Down Expand Up @@ -110,9 +110,9 @@ export const TradeAssetSearch: FC<TradeAssetSearchProps> = ({

const popularAssets = useMemo(() => {
const unfilteredPopularAssets = popularAssetsByChainId?.[activeChainId] ?? []
const filteredPopularAssets = assetFilterPredicate
? unfilteredPopularAssets.filter(assetFilterPredicate)
: unfilteredPopularAssets
const filteredPopularAssets = unfilteredPopularAssets.filter(
asset => assetFilterPredicate?.(asset.assetId) ?? true,
)
if (allowWalletUnsupportedAssets || !hasWallet) return filteredPopularAssets

// TODO: move `allowWalletUnsupportedAssets` into `assetFilterPredicate`
Expand Down Expand Up @@ -150,9 +150,9 @@ export const TradeAssetSearch: FC<TradeAssetSearchProps> = ({
}, [activeChainId, popularAssets])

const portfolioAssetsSortedByBalanceForChain = useMemo(() => {
const filteredPortfolioAssetsSortedByBalance = assetFilterPredicate
? portfolioAssetsSortedByBalance.filter(assetFilterPredicate)
: portfolioAssetsSortedByBalance
const filteredPortfolioAssetsSortedByBalance = portfolioAssetsSortedByBalance.filter(
asset => assetFilterPredicate?.(asset.assetId) ?? true,
)

if (activeChainId === 'All') {
return filteredPortfolioAssetsSortedByBalance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ChainId } from '@shapeshiftoss/caip'
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import { ASSET_NAMESPACE, bscChainId, isNft, toAssetId } from '@shapeshiftoss/caip'
import { isEvmChainId } from '@shapeshiftoss/chain-adapters'
import type { Asset } from '@shapeshiftoss/types'
Expand All @@ -25,7 +25,7 @@ export type SearchTermAssetListProps = {
activeChainId: ChainId | 'All'
searchString: string
allowWalletUnsupportedAssets: boolean | undefined
assetFilterPredicate?: (asset: Asset) => boolean
assetFilterPredicate?: (assetId: AssetId) => boolean
onAssetClick: (asset: Asset) => void
onImportClick: (asset: Asset) => void
}
Expand Down Expand Up @@ -61,7 +61,7 @@ export const SearchTermAssetList = ({
})

const assetsForChain = useMemo(() => {
const _assets = assetFilterPredicate ? assets.filter(assetFilterPredicate) : assets
const _assets = assets.filter(asset => assetFilterPredicate?.(asset.assetId) ?? true)
if (activeChainId === 'All') {
if (allowWalletUnsupportedAssets) return _assets
return _assets.filter(
Expand Down

0 comments on commit a18c817

Please sign in to comment.