Skip to content

Commit

Permalink
Feat: cached safe overviews (#4221)
Browse files Browse the repository at this point in the history
* feat: fetch safe overviews using rtk query
* fix: do not load safe overview for undeployed Safes
  • Loading branch information
schmanu authored Sep 25, 2024
1 parent a701240 commit ea83b21
Show file tree
Hide file tree
Showing 27 changed files with 579 additions and 177 deletions.
41 changes: 25 additions & 16 deletions src/components/common/NetworkSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,34 @@ import { useAllSafesGrouped } from '@/components/welcome/MyAccounts/useAllSafesG
import useSafeAddress from '@/hooks/useSafeAddress'
import { sameAddress } from '@/utils/addresses'
import uniq from 'lodash/uniq'
import useSafeOverviews from '@/components/welcome/MyAccounts/useSafeOverviews'
import { useCompatibleNetworks } from '@/features/multichain/hooks/useCompatibleNetworks'
import { useSafeCreationData } from '@/features/multichain/hooks/useSafeCreationData'
import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import PlusIcon from '@/public/images/common/plus.svg'
import useAddressBook from '@/hooks/useAddressBook'
import { CreateSafeOnSpecificChain } from '@/features/multichain/components/CreateSafeOnNewChain'
import { useGetSafeOverviewQuery } from '@/store/api/gateway'

const ChainIndicatorWithFiatBalance = ({
isSelected,
chain,
safeAddress,
}: {
isSelected: boolean
chain: ChainInfo
safeAddress: string
}) => {
const { data: safeOverview } = useGetSafeOverviewQuery({ safeAddress, chainId: chain.chainId })

return (
<ChainIndicator
responsive={isSelected}
chainId={chain.chainId}
fiatValue={safeOverview ? safeOverview.fiatTotal : undefined}
inline
/>
)
}

export const getNetworkLink = (router: NextRouter, safeAddress: string, networkShortName: string) => {
const isSafeOpened = safeAddress !== ''
Expand Down Expand Up @@ -272,12 +293,6 @@ const NetworkSelector = ({
[availableChainIds, configs],
)

const multiChainSafes = useMemo(
() => availableChainIds.map((chain) => ({ address: safeAddress, chainId: chain })),
[availableChainIds, safeAddress],
)
const [safeOverviews] = useSafeOverviews(multiChainSafes)

const onChange = (event: SelectChangeEvent) => {
event.preventDefault() // Prevent the link click

Expand All @@ -293,9 +308,8 @@ const NetworkSelector = ({

const renderMenuItem = useCallback(
(chainId: string, isSelected: boolean) => {
useChainId
const chain = chains.data.find((chain) => chain.chainId === chainId)
const safeOverview = safeOverviews?.find((overview) => chainId === overview.chainId)

if (!chain) return null

return (
Expand All @@ -305,17 +319,12 @@ const NetworkSelector = ({
onClick={onChainSelect}
className={css.item}
>
<ChainIndicator
responsive={isSelected}
chainId={chain.chainId}
fiatValue={safeOverview ? safeOverview.fiatTotal : undefined}
inline
/>
<ChainIndicatorWithFiatBalance chain={chain} safeAddress={safeAddress} isSelected={isSelected} />
</Link>
</MenuItem>
)
},
[chains.data, onChainSelect, router, safeAddress, safeOverviews],
[chains.data, onChainSelect, router, safeAddress],
)

return configs.length ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import SafeTokenWidget from '..'
import { toBeHex } from 'ethers'
import { AppRoutes } from '@/config/routes'
import useSafeTokenAllocation, { useSafeVotingPower } from '@/hooks/useSafeTokenAllocation'
import * as safePass from '@/store/safePass'
import type { CampaignLeaderboardEntry } from '@/store/safePass'
import * as safePass from '@/store/api/safePass'
import type { CampaignLeaderboardEntry } from '@/store/api/safePass'

jest.mock('@/hooks/useChainId')

Expand Down
2 changes: 1 addition & 1 deletion src/components/common/SafeTokenWidget/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import css from './styles.module.css'
import useSafeAddress from '@/hooks/useSafeAddress'
import { skipToken } from '@reduxjs/toolkit/query/react'
import { useDarkMode } from '@/hooks/useDarkMode'
import { useGetOwnGlobalCampaignRankQuery } from '@/store/safePass'
import { useGetOwnGlobalCampaignRankQuery } from '@/store/api/safePass'
import { formatAmount } from '@/utils/formatNumber'

const TOKEN_DECIMALS = 18
Expand Down
2 changes: 1 addition & 1 deletion src/components/transactions/SingleTx/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ExpandableTransactionItem, {
} from '@/components/transactions/TxListItem/ExpandableTransactionItem'
import GroupLabel from '../GroupLabel'
import { isMultisigDetailedExecutionInfo } from '@/utils/transaction-guards'
import { useGetTransactionDetailsQuery } from '@/store/gateway'
import { useGetTransactionDetailsQuery } from '@/store/api/gateway'
import { skipToken } from '@reduxjs/toolkit/query/react'
import { asError } from '@/services/exceptions/utils'

Expand Down
2 changes: 1 addition & 1 deletion src/components/transactions/TxDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import useIsPending from '@/hooks/useIsPending'
import { isImitation, isTrustedTx } from '@/utils/transactions'
import { useHasFeature } from '@/hooks/useChains'
import { FEATURES } from '@/utils/chains'
import { useGetTransactionDetailsQuery } from '@/store/gateway'
import { useGetTransactionDetailsQuery } from '@/store/api/gateway'
import { asError } from '@/services/exceptions/utils'
import { POLLING_INTERVAL } from '@/config/constants'

Expand Down
2 changes: 1 addition & 1 deletion src/components/tx-flow/flows/ExecuteBatch/ReviewBatch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import WalletRejectionError from '@/components/tx/SignOrExecuteForm/WalletReject
import useUserNonce from '@/components/tx/AdvancedParams/useUserNonce'
import { getLatestSafeVersion } from '@/utils/chains'
import { HexEncodedData } from '@/components/transactions/HexEncodedData'
import { useGetMultipleTransactionDetailsQuery } from '@/store/gateway'
import { useGetMultipleTransactionDetailsQuery } from '@/store/api/gateway'
import { skipToken } from '@reduxjs/toolkit/query/react'
import NetworkWarning from '@/components/new-safe/create/NetworkWarning'

Expand Down
2 changes: 1 addition & 1 deletion src/components/tx/DecodedTx/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import DecodedData from '@/components/transactions/TxDetails/TxData/DecodedData'
import accordionCss from '@/styles/accordion.module.css'
import HelpToolTip from './HelpTooltip'
import { useGetTransactionDetailsQuery } from '@/store/gateway'
import { useGetTransactionDetailsQuery } from '@/store/api/gateway'
import { skipToken } from '@reduxjs/toolkit/query/react'
import { asError } from '@/services/exceptions/utils'

Expand Down
2 changes: 1 addition & 1 deletion src/components/tx/SignOrExecuteForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { MigrateToL2Information } from './MigrateToL2Information'
import { extractMigrationL2MasterCopyAddress } from '@/utils/transactions'

import type { TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk'
import { useGetTransactionDetailsQuery, useLazyGetTransactionDetailsQuery } from '@/store/gateway'
import { useGetTransactionDetailsQuery, useLazyGetTransactionDetailsQuery } from '@/store/api/gateway'
import { skipToken } from '@reduxjs/toolkit/query/react'
import NetworkWarning from '@/components/new-safe/create/NetworkWarning'

Expand Down
16 changes: 15 additions & 1 deletion src/components/welcome/MyAccounts/AccountItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ import FiatValue from '@/components/common/FiatValue'
import QueueActions from './QueueActions'
import { useGetHref } from './useGetHref'
import { extractCounterfactualSafeSetup, isPredictedSafeProps } from '@/features/counterfactual/utils'
import { useGetSafeOverviewQuery } from '@/store/api/gateway'
import useWallet from '@/hooks/wallets/useWallet'
import { skipToken } from '@reduxjs/toolkit/query'

type AccountItemProps = {
safeItem: SafeItem
safeOverview?: SafeOverview
onLinkClick?: () => void
}

const AccountItem = ({ onLinkClick, safeItem, safeOverview }: AccountItemProps) => {
const AccountItem = ({ onLinkClick, safeItem }: AccountItemProps) => {
const { chainId, address } = safeItem
const chain = useAppSelector((state) => selectChainById(state, chainId))
const undeployedSafe = useAppSelector((state) => selectUndeployedSafe(state, chainId, address))
Expand All @@ -42,6 +45,7 @@ const AccountItem = ({ onLinkClick, safeItem, safeOverview }: AccountItemProps)
const router = useRouter()
const isCurrentSafe = chainId === currChainId && sameAddress(safeAddress, address)
const isWelcomePage = router.pathname === AppRoutes.welcome.accounts
const { address: walletAddress } = useWallet() ?? {}

const trackingLabel = isWelcomePage ? OVERVIEW_LABELS.login_page : OVERVIEW_LABELS.sidebar

Expand All @@ -61,6 +65,16 @@ const AccountItem = ({ onLinkClick, safeItem, safeOverview }: AccountItemProps)

const isReplayable = !safeItem.isWatchlist && (!undeployedSafe || !isPredictedSafeProps(undeployedSafe.props))

const { data: safeOverview } = useGetSafeOverviewQuery(
undeployedSafe
? skipToken
: {
chainId: safeItem.chainId,
safeAddress: safeItem.address,
walletAddress,
},
)

return (
<ListItemButton
data-testid="safe-list-item"
Expand Down
28 changes: 21 additions & 7 deletions src/components/welcome/MyAccounts/MultiAccountItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { selectUndeployedSafes } from '@/features/counterfactual/store/undeployedSafesSlice'
import type { SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
import { useMemo, useState } from 'react'
import { useCallback, useMemo, useState } from 'react'
import {
ListItemButton,
Box,
Expand Down Expand Up @@ -33,6 +33,9 @@ import { AddNetworkButton } from './AddNetworkButton'
import { isPredictedSafeProps } from '@/features/counterfactual/utils'
import ChainIndicator from '@/components/common/ChainIndicator'
import MultiAccountContextMenu from '@/components/sidebar/SafeListContextMenu/MultiAccountContextMenu'
import { useGetMultipleSafeOverviewsQuery } from '@/store/api/gateway'
import useWallet from '@/hooks/wallets/useWallet'
import { selectCurrency } from '@/store/settingsSlice'

type MultiAccountItemProps = {
multiSafeAccountItem: MultiChainSafeItem
Expand Down Expand Up @@ -62,7 +65,7 @@ const MultichainIndicator = ({ safes }: { safes: SafeItem[] }) => {
)
}

const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, safeOverviews }: MultiAccountItemProps) => {
const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem }: MultiAccountItemProps) => {
const { address, safes } = multiSafeAccountItem
const undeployedSafes = useAppSelector(selectUndeployedSafes)
const safeAddress = useSafeAddress()
Expand Down Expand Up @@ -90,6 +93,14 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, safeOverviews }:
return Object.values(allAddressBooks).find((ab) => ab[address] !== undefined)?.[address]
}, [address, allAddressBooks])

const currency = useAppSelector(selectCurrency)
const { address: walletAddress } = useWallet() ?? {}
const deployedSafes = useMemo(
() => safes.filter((safe) => undeployedSafes[safe.chainId]?.[safe.address] === undefined),
[safes, undeployedSafes],
)
const { data: safeOverviews } = useGetMultipleSafeOverviewsQuery({ currency, walletAddress, safes: deployedSafes })

const safeSetups = useMemo(
() => getSafeSetups(safes, safeOverviews ?? [], undeployedSafes),
[safeOverviews, safes, undeployedSafes],
Expand All @@ -111,11 +122,14 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, safeOverviews }:
[safes, undeployedSafes],
)

const findOverview = (item: SafeItem) => {
return safeOverviews?.find(
(overview) => item.chainId === overview.chainId && sameAddress(overview.address.value, item.address),
)
}
const findOverview = useCallback(
(item: SafeItem) => {
return safeOverviews?.find(
(overview) => item.chainId === overview.chainId && sameAddress(overview.address.value, item.address),
)
},
[safeOverviews],
)

return (
<ListItemButton
Expand Down
28 changes: 2 additions & 26 deletions src/components/welcome/MyAccounts/PaginatedSafeList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { Paper, Typography } from '@mui/material'
import AccountItem from './AccountItem'
import { type SafeItem } from './useAllSafes'
import css from './styles.module.css'
import useSafeOverviews from './useSafeOverviews'
import { sameAddress } from '@/utils/addresses'
import InfiniteScroll from '@/components/common/InfiniteScroll'
import { type MultiChainSafeItem } from './useAllSafesGrouped'
import MultiAccountItem from './MultiAccountItem'
Expand All @@ -26,35 +24,13 @@ type SafeListPageProps = {
const DEFAULT_PAGE_SIZE = 10

export const SafeListPage = ({ safes, onLinkClick }: SafeListPageProps) => {
const flattenedSafes = useMemo(
() => safes.flatMap((safe) => (isMultiChainSafeItem(safe) ? safe.safes : safe)),
[safes],
)
const [overviews] = useSafeOverviews(flattenedSafes)

const findOverview = (item: SafeItem) => {
return overviews?.find(
(overview) => item.chainId === overview.chainId && sameAddress(overview.address.value, item.address),
)
}

return (
<>
{safes.map((item) =>
isMultiChainSafeItem(item) ? (
<MultiAccountItem
onLinkClick={onLinkClick}
key={item.address}
multiSafeAccountItem={item}
safeOverviews={overviews?.filter((overview) => sameAddress(overview.address.value, item.address))}
/>
<MultiAccountItem onLinkClick={onLinkClick} key={item.address} multiSafeAccountItem={item} />
) : (
<AccountItem
onLinkClick={onLinkClick}
safeItem={item}
safeOverview={findOverview(item)}
key={item.chainId + item.address}
/>
<AccountItem onLinkClick={onLinkClick} safeItem={item} key={item.chainId + item.address} />
),
)}
</>
Expand Down

This file was deleted.

Loading

0 comments on commit ea83b21

Please sign in to comment.