Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: cached safe overviews #4221

Merged
merged 7 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/safeOverviews'

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
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/safeOverviews'
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/safeOverviews'
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.

49 changes: 0 additions & 49 deletions src/components/welcome/MyAccounts/useSafeOverviews.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import useChains, { useCurrentChain } from '@/hooks/useChains'
import ErrorMessage from '@/components/tx/ErrorMessage'
import useSafeAddress from '@/hooks/useSafeAddress'
import { useAppSelector } from '@/store'
import { selectUndeployedSafes } from '@/store/slices'
import { selectCurrency, selectUndeployedSafes, useGetMultipleSafeOverviewsQuery } from '@/store/slices'
import { useAllSafesGrouped } from '@/components/welcome/MyAccounts/useAllSafesGrouped'
import { sameAddress } from '@/utils/addresses'
import useSafeOverviews from '@/components/welcome/MyAccounts/useSafeOverviews'
import { useMemo } from 'react'
import { getDeviatingSetups, getSafeSetups } from '@/components/welcome/MyAccounts/utils/multiChainSafe'
import { Box, Typography } from '@mui/material'
Expand Down Expand Up @@ -37,14 +36,19 @@ export const InconsistentSignerSetupWarning = () => {
const isMultichainSafe = useIsMultichainSafe()
const safeAddress = useSafeAddress()
const currentChain = useCurrentChain()
const currency = useAppSelector(selectCurrency)
const undeployedSafes = useAppSelector(selectUndeployedSafes)
const { allMultiChainSafes } = useAllSafesGrouped()

const multiChainGroupSafes = useMemo(
() => allMultiChainSafes?.find((account) => sameAddress(safeAddress, account.safes[0].address))?.safes ?? [],
[allMultiChainSafes, safeAddress],
)
const [safeOverviews] = useSafeOverviews(multiChainGroupSafes)
const deployedSafes = useMemo(
() => multiChainGroupSafes.filter((safe) => undeployedSafes[safe.chainId]?.[safe.address] === undefined),
[multiChainGroupSafes, undeployedSafes],
)
const { data: safeOverviews } = useGetMultipleSafeOverviewsQuery({ safes: deployedSafes, currency })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to pass the walletAddress here as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not pass it to have less dependencies and more likely cache hits.
This component is only interested in the signers and the threshold. The wallet address fetches the pending actions which is not needed here.


const safeSetups = useMemo(
() => getSafeSetups(multiChainGroupSafes, safeOverviews ?? [], undeployedSafes),
Expand Down
Loading
Loading