Skip to content

Commit

Permalink
feat: improve reactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre committed Sep 7, 2023
1 parent 7c1a1c6 commit 3cd2e2c
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 55 deletions.
4 changes: 3 additions & 1 deletion src/components/AssetHeader/AssetHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useMemo } from 'react'
import { useTranslate } from 'react-polyglot'
import { AssetIcon } from 'components/AssetIcon'
import { SEO } from 'components/Layout/Seo'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useLocaleFormatter } from 'hooks/useLocaleFormatter/useLocaleFormatter'
import { useWallet } from 'hooks/useWallet/useWallet'
import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
Expand Down Expand Up @@ -48,7 +49,8 @@ export const AssetHeader: React.FC<AssetHeaderProps> = ({ assetId, accountId, ..
state: { wallet },
} = useWallet()

const walletSupportsChain = useWalletSupportsChain({ chainId, wallet })
const isSnapInstalled = useIsSnapInstalled()
const walletSupportsChain = useWalletSupportsChain({ chainId, wallet, isSnapInstalled })

const filter = useMemo(() => ({ assetId, accountId }), [assetId, accountId])
const cryptoBalance =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { AddressInput } from 'components/Modals/Send/AddressInput/AddressInput'
import { SendFormFields } from 'components/Modals/Send/SendCommon'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { useFeatureFlag } from 'hooks/useFeatureFlag/useFeatureFlag'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { parseAddressInputWithChainId } from 'lib/address/address'
Expand All @@ -31,7 +32,12 @@ export const ManualAddressEntry: FC = memo((): JSX.Element | null => {
const isYatSupportedByReceiveChain = buyAssetChainId === ethChainId // yat only supports eth mainnet
const isYatSupported = isYatFeatureEnabled && isYatSupportedByReceiveChain

const walletSupportsBuyAssetChain = useWalletSupportsChain({ chainId: buyAssetChainId, wallet })
const isSnapInstalled = useIsSnapInstalled()
const walletSupportsBuyAssetChain = useWalletSupportsChain({
chainId: buyAssetChainId,
wallet,
isSnapInstalled,
})
const shouldShowManualReceiveAddressInput = !walletSupportsBuyAssetChain

const chainAdapterManager = getChainAdapterManager()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { AssetId } from '@shapeshiftoss/caip'
import { useMemo } from 'react'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { walletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { bnOrZero } from 'lib/bignumber/bignumber'
import type { ProtocolFee } from 'lib/swapper/types'
import { selectPortfolioAccountBalancesBaseUnit } from 'state/slices/common-selectors'
Expand All @@ -27,11 +28,16 @@ export const useInsufficientBalanceProtocolFeeMeta = () => {
)

const lastHopBuyAsset = useAppSelector(selectLastHopBuyAsset)

const isSnapInstalled = useIsSnapInstalled()

const walletSupportsBuyAssetChain =
useWalletSupportsChain({
chainId: lastHopBuyAsset?.chainId ?? '',
lastHopBuyAsset &&
walletSupportsChain({
chainId: lastHopBuyAsset.chainId,
wallet,
}) && lastHopBuyAsset
isSnapInstalled,
})

const totalProtocolFees = useAppSelector(selectTotalProtocolFeeByAsset)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { useHopHelper } from 'components/MultiHopTrade/hooks/useHopHelper'
import { useIsTradingActive } from 'components/MultiHopTrade/hooks/useIsTradingActive'
import { useReceiveAddress } from 'components/MultiHopTrade/hooks/useReceiveAddress'
import { ActiveQuoteStatus } from 'components/MultiHopTrade/types'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { walletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { bnOrZero } from 'lib/bignumber/bignumber'
import { isTruthy } from 'lib/utils'
import { selectSwappersApiTradeQuotes } from 'state/apis/swappers/selectors'
Expand Down Expand Up @@ -44,16 +45,22 @@ export const useQuoteValidationErrors = (): ActiveQuoteStatus[] => {
const manualReceiveAddress = useAppSelector(selectManualReceiveAddress)
const quotes = useAppSelector(selectSwappersApiTradeQuotes)

const isSnapInstalled = useIsSnapInstalled()

const walletSupportsSellAssetChain =
useWalletSupportsChain({
chainId: firstHopSellAsset?.chainId ?? '',
firstHopSellAsset &&
walletSupportsChain({
chainId: firstHopSellAsset.chainId,
wallet,
}) && firstHopSellAsset
isSnapInstalled,
})
const walletSupportsBuyAssetChain =
useWalletSupportsChain({
chainId: lastHopBuyAsset?.chainId ?? '',
lastHopBuyAsset &&
walletSupportsChain({
chainId: lastHopBuyAsset.chainId,
wallet,
}) && lastHopBuyAsset
isSnapInstalled,
})

const hasSufficientSellAssetBalance = bnOrZero(sellAssetBalanceCryptoBaseUnit).gte(
bnOrZero(sellAmountCryptoBaseUnit),
Expand Down
6 changes: 4 additions & 2 deletions src/components/MultiHopTrade/hooks/useSupportedAssets.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AssetId } from '@shapeshiftoss/caip'
import { fromAssetId } from '@shapeshiftoss/caip'
import { useEffect, useMemo, useState } from 'react'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { walletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import type { Asset } from 'lib/asset-service'
Expand All @@ -23,19 +24,20 @@ export const useSupportedAssets = () => {
const [supportedBuyAssets, setSupportedBuyAssets] = useState<Asset[]>([])
const [supportedBuyAssetsIds, setSupportedBuyAssetsIds] = useState<Set<AssetId>>(new Set())

const isSnapInstalled = useIsSnapInstalled()
useEffect(() => {
;(async () => {
const assetIds = await getSupportedSellAssetIds(enabledSwappers)
const filteredAssetIds = new Set<AssetId>()
assetIds.forEach(async assetId => {
const chainId = fromAssetId(assetId).chainId
if (await walletSupportsChain({ chainId, wallet })) {
if (await walletSupportsChain({ chainId, wallet, isSnapInstalled })) {
filteredAssetIds.add(assetId)
}
})
setSupportedSellAssetIds(filteredAssetIds)
})()
}, [enabledSwappers, sortedAssets, wallet])
}, [enabledSwappers, isSnapInstalled, sortedAssets, wallet])

useEffect(() => {
;(async () => {
Expand Down
12 changes: 9 additions & 3 deletions src/components/StakingVaults/PositionTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PositionDetails } from 'components/EarnDashboard/components/PositionDet
import { ReactTable } from 'components/ReactTable/ReactTable'
import { ResultsEmpty } from 'components/ResultsEmpty'
import { RawText } from 'components/Text'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { walletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { isEthAddress } from 'lib/address/utils'
Expand Down Expand Up @@ -88,13 +89,18 @@ export const PositionTable: React.FC<PositionTableProps> = ({
),
)

const isSnapInstalled = useIsSnapInstalled()

const filteredPositions = useMemo(
() =>
positions.filter(position =>
// TODO(gomes): await this, this will now break
walletSupportsChain({ chainId: fromAssetId(position.assetId).chainId, wallet }),
walletSupportsChain({
chainId: fromAssetId(position.assetId).chainId,
wallet,
isSnapInstalled,
}),
),
[positions, wallet],
[isSnapInstalled, positions, wallet],
)

const columns: Column<AggregatedOpportunitiesByAssetIdReturn>[] = useMemo(
Expand Down
9 changes: 5 additions & 4 deletions src/components/StakingVaults/ProviderCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { WalletLpByAsset } from 'components/EarnDashboard/components/ProviderDet
import { WalletStakingByAsset } from 'components/EarnDashboard/components/ProviderDetails/WalletStakingByAsset'
import { LazyLoadAvatar } from 'components/LazyLoadAvatar'
import { RawText } from 'components/Text'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { walletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import type {
Expand Down Expand Up @@ -50,20 +51,20 @@ export const ProviderCard: React.FC<ProviderCardProps> = ({
selectAggregatedEarnUserStakingOpportunitiesIncludeEmpty,
)

const isSnapInstalled = useIsSnapInstalled()

const filteredDownStakingOpportunities = stakingOpportunities.filter(
e =>
staking.includes(e.id as OpportunityId) &&
// TODO(gomes): await this, this will now break
walletSupportsChain({ chainId: e.chainId, wallet }),
walletSupportsChain({ chainId: e.chainId, wallet, isSnapInstalled }),
)

const lpOpportunities = useAppSelector(selectAggregatedEarnUserLpOpportunities)

const filteredDownLpOpportunities = lpOpportunities.filter(
e =>
lp.includes(e.assetId as OpportunityId) &&
// TODO(gomes): await this, this will now break
walletSupportsChain({ chainId: e.chainId, wallet }),
walletSupportsChain({ chainId: e.chainId, wallet, isSnapInstalled }),
)

if (!filteredDownLpOpportunities.length && !filteredDownStakingOpportunities.length) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useTranslate } from 'react-polyglot'
import { useLocation } from 'react-router'
import { NavLink } from 'react-router-dom'
import { TransactionHistoryList } from 'components/TransactionHistory/TransactionHistoryList'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { useWallet } from 'hooks/useWallet/useWallet'
import { useWalletSupportsChain } from 'hooks/useWalletSupportsChain/useWalletSupportsChain'
import { selectAssetById, selectTxIdsByFilter } from 'state/slices/selectors'
Expand Down Expand Up @@ -35,7 +36,8 @@ export const AssetTransactionHistory: React.FC<AssetTransactionHistoryProps> = (
const chainId: ChainId = asset?.chainId ?? ''

const filter = useMemo(() => ({ assetId, accountId }), [assetId, accountId])
const walletSupportsChain = useWalletSupportsChain({ chainId, wallet })
const isSnapInstalled = useIsSnapInstalled()
const walletSupportsChain = useWalletSupportsChain({ chainId, wallet, isSnapInstalled })
const txIds = useAppSelector(state => selectTxIdsByFilter(state, filter))

if (!assetId) return null
Expand Down
9 changes: 2 additions & 7 deletions src/context/AppProvider/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,8 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
useEffect(() => {
if (!wallet) return
;(async () => {
const chainIds = await Array.from(supportedChains).reduce<Promise<ChainId[]>>(
async (acc, chainId) => {
const isChainSupported = await walletSupportsChain({ chainId, wallet })
if (isChainSupported) return Promise.resolve([...(await acc), chainId])
return acc
},
Promise.resolve([]),
const chainIds = Array.from(supportedChains).filter(chainId =>
walletSupportsChain({ chainId, wallet, isSnapInstalled }),
)
const isMultiAccountWallet = wallet.supportsBip44Accounts()
for (let accountNumber = 0; chainIds.length > 0; accountNumber++) {
Expand Down
42 changes: 19 additions & 23 deletions src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,23 @@ import {
supportsThorchain,
} from '@shapeshiftoss/hdwallet-core'
import { MetaMaskShapeShiftMultiChainHDWallet } from '@shapeshiftoss/hdwallet-shapeshift-multichain'
import { shapeShiftSnapInstalled } from '@shapeshiftoss/metamask-snaps-adapter'
import { getConfig } from 'config'
import { useEffect, useState } from 'react'
import { useIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'

type UseWalletSupportsChainArgs = { chainId: ChainId; wallet: HDWallet | null }
type UseWalletSupportsChainArgs = {
isSnapInstalled: boolean | null
chainId: ChainId
wallet: HDWallet | null
}
type UseWalletSupportsChain = (args: UseWalletSupportsChainArgs) => boolean | null
type UseWalletSupportsChainAsync = (args: UseWalletSupportsChainArgs) => Promise<boolean>

// use outside react
export const walletSupportsChain: UseWalletSupportsChainAsync = async ({ chainId, wallet }) => {
export const walletSupportsChain: UseWalletSupportsChain = ({
chainId,
wallet,
isSnapInstalled,
}) => {
if (!wallet) return false
const isMetaMaskMultichainWallet = wallet instanceof MetaMaskShapeShiftMultiChainHDWallet
// We might be in a state where the wallet adapter is MetaMaskShapeShiftMultiChainHDWallet, but the actual underlying either
// - doesn't support snaps (as snaps are currently only in Flask canary build at the time of writing) or
// - supports snaps, but the snaps isn't installed
// This should obviously belong at hdwallet-core, and feature detection should be made async, with hdwallet-shapeshift-multichain able to do feature detection
// programatically depending on whether the snaps is installed or not, but in the meantime, this will make things happy
const snapId = getConfig().REACT_APP_SNAP_ID
const isSnapInstalled = await shapeShiftSnapInstalled(snapId)
// If this evaluates to false, the wallet feature detection will be short circuit
const skipWalletFeatureDetection =
!isMetaMaskMultichainWallet || (isMetaMaskMultichainWallet && isSnapInstalled)
switch (chainId) {
Expand Down Expand Up @@ -77,14 +74,13 @@ export const walletSupportsChain: UseWalletSupportsChainAsync = async ({ chainId
}

export const useWalletSupportsChain: UseWalletSupportsChain = args => {
const [supported, setSupported] = useState<boolean | null>(null)

useEffect(() => {
;(async () => {
const result = await walletSupportsChain(args)
setSupported(result)
})()
}, [args])
// We might be in a state where the wallet adapter is MetaMaskShapeShiftMultiChainHDWallet, but the actual underlying either
// - doesn't support snaps (as snaps are currently only in Flask canary build at the time of writing) or
// - supports snaps, but the snaps isn't installed
// This should obviously belong at hdwallet-core, and feature detection should be made async, with hdwallet-shapeshift-multichain able to do feature detection
// programatically depending on whether the snaps is installed or not, but in the meantime, this will make things happy
// If this evaluates to false, the wallet feature detection will be short circuit
const isSnapInstalled = useIsSnapInstalled()

return supported
return walletSupportsChain({ ...args, isSnapInstalled })
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ const allNamespacesSupported = (
): boolean =>
Object.values(requiredNamespaces).every(
requiredNamespace =>
// TODO(gomes): fix this
requiredNamespace.chains?.every(chainId => walletSupportsChain({ chainId, wallet })),
requiredNamespace.chains?.every(chainId =>
// TODO(gomes): fix this
walletSupportsChain({ chainId, wallet, isSnapInstalled: false }),
),
)

const createApprovalNamespaces = (
Expand Down

0 comments on commit 3cd2e2c

Please sign in to comment.