Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/epic/multichain-safes' into feat…
Browse files Browse the repository at this point in the history
…/explain-impossible-network-addition
  • Loading branch information
schmanu committed Oct 1, 2024
2 parents 7e1db2e + bfcbba1 commit cfc732e
Show file tree
Hide file tree
Showing 20 changed files with 331 additions and 123 deletions.
6 changes: 5 additions & 1 deletion src/components/common/ModalDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ interface DialogTitleProps {

export const ModalDialogTitle = ({ children, onClose, hideChainIndicator = false, ...other }: DialogTitleProps) => {
return (
<DialogTitle data-testid="modal-title" sx={{ m: 0, p: 2, display: 'flex', alignItems: 'center' }} {...other}>
<DialogTitle
data-testid="modal-title"
sx={{ m: 0, px: 3, pt: 3, pb: 2, display: 'flex', alignItems: 'center', fontWeight: 'bold' }}
{...other}
>
{children}
<span style={{ flex: 1 }} />
{!hideChainIndicator && <ChainIndicator inline />}
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/ModalDialog/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.dialog :global .MuiDialogActions-root {
border-top: 1px solid var(--color-border-light);
padding: var(--space-3);
padding: var(--space-2) var(--space-3);
}

.dialog :global .MuiDialogActions-root > :last-of-type:not(:first-of-type) {
Expand Down
43 changes: 25 additions & 18 deletions src/components/common/NetworkSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import useAddressBook from '@/hooks/useAddressBook'
import { CreateSafeOnSpecificChain } from '@/features/multichain/components/CreateSafeOnNewChain'
import { useGetSafeOverviewQuery } from '@/store/api/gateway'
import { InfoOutlined } from '@mui/icons-material'
import { selectUndeployedSafe } from '@/store/slices'
import { skipToken } from '@reduxjs/toolkit/query'

const ChainIndicatorWithFiatBalance = ({
isSelected,
Expand All @@ -50,7 +52,10 @@ const ChainIndicatorWithFiatBalance = ({
chain: ChainInfo
safeAddress: string
}) => {
const { data: safeOverview } = useGetSafeOverviewQuery({ safeAddress, chainId: chain.chainId })
const undeployedSafe = useAppSelector((state) => selectUndeployedSafe(state, chain.chainId, safeAddress))
const { data: safeOverview } = useGetSafeOverviewQuery(
undeployedSafe ? skipToken : { safeAddress, chainId: chain.chainId },
)

return (
<ChainIndicator
Expand Down Expand Up @@ -102,23 +107,25 @@ const UndeployedNetworkMenuItem = ({

return (
<Track {...OVERVIEW_EVENTS.ADD_NEW_NETWORK} label={OVERVIEW_LABELS.top_bar}>
<MenuItem
value={chain.chainId}
sx={{ '&:hover': { backgroundColor: 'inherit' } }}
onClick={() => onSelect(chain)}
disabled={isDisabled}
>
<Box className={css.item}>
<ChainIndicator responsive={isSelected} chainId={chain.chainId} inline />
{isDisabled ? (
<Typography variant="caption" component="span" className={css.comingSoon}>
Not available
</Typography>
) : (
<PlusIcon className={css.plusIcon} />
)}
</Box>
</MenuItem>
<Tooltip title="Add network" arrow placement="left">
<MenuItem
value={chain.chainId}
sx={{ '&:hover': { backgroundColor: 'inherit' } }}
onClick={() => onSelect(chain)}
disabled={isDisabled}
>
<Box className={css.item}>
<ChainIndicator responsive={isSelected} chainId={chain.chainId} inline />
{isDisabled ? (
<Typography variant="caption" component="span" className={css.comingSoon}>
Not available
</Typography>
) : (
<PlusIcon className={css.plusIcon} />
)}
</Box>
</MenuItem>
</Tooltip>
</Track>
)
}
Expand Down
1 change: 1 addition & 0 deletions src/components/common/NetworkSelector/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
.multiChainChip {
padding: var(--space-2) 0;
margin: 2px;
border-color: var(--color-border-main);
}

.comingSoon {
Expand Down
20 changes: 13 additions & 7 deletions src/components/dashboard/FirstSteps/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useAppDispatch, useAppSelector } from '@/store'
import { selectSettings, setQrShortName } from '@/store/settingsSlice'
import { selectOutgoingTransactions } from '@/store/txHistorySlice'
import { getExplorerLink } from '@/utils/gateway'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import classnames from 'classnames'
import { type ReactNode, useState } from 'react'
import { Card, WidgetBody, WidgetContainer } from '@/components/dashboard/styled'
Expand Down Expand Up @@ -59,7 +60,9 @@ const StatusCard = ({
<Typography variant="h4" fontWeight="bold" mb={2}>
{title}
</Typography>
<Typography>{content}</Typography>
<Typography variant="body2" color="primary.light">
{content}
</Typography>
{children}
</Card>
)
Expand Down Expand Up @@ -259,24 +262,27 @@ const FirstTransactionWidget = ({ completed }: { completed: boolean }) => {
)
}

const ActivateSafeWidget = () => {
const ActivateSafeWidget = ({ chain }: { chain: ChainInfo | undefined }) => {
const [open, setOpen] = useState<boolean>(false)

const title = 'Activate your Safe account.'
const title = `Activate account ${chain ? 'on ' + chain.chainName : ''}`
const content = 'Activate your account to start using all benefits of Safe'

return (
<>
<StatusCard
badge={
<Typography variant="body2" className={css.badgeText}>
Activate your Safe
First interaction
</Typography>
}
title={title}
completed={false}
content=""
content={content}
>
<ActivateAccountButton />
<Box mt={2}>
<ActivateAccountButton />
</Box>
</StatusCard>
<FirstTxFlow open={open} onClose={() => setOpen(false)} />
</>
Expand Down Expand Up @@ -386,7 +392,7 @@ const FirstSteps = () => {
{isActivating ? (
<UsefulHintsWidget />
) : isMultiSig || isReplayedSafe ? (
<ActivateSafeWidget />
<ActivateSafeWidget chain={chain} />
) : (
<FirstTransactionWidget completed={hasOutgoingTransactions} />
)}
Expand Down
47 changes: 47 additions & 0 deletions src/components/settings/FallbackHandler/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TWAP_FALLBACK_HANDLER } from '@/features/swap/helpers/utils'
import { chainBuilder } from '@/tests/builders/chains'
import { render, waitFor } from '@/tests/test-utils'

Expand Down Expand Up @@ -238,4 +239,50 @@ describe('FallbackHandler', () => {

expect(fbHandler.container).toBeEmptyDOMElement()
})

it('should display a message in case it is a TWAP fallback handler', () => {
jest.spyOn(useSafeInfoHook, 'default').mockImplementation(
() =>
({
safe: {
version: '1.3.0',
chainId: '1',
fallbackHandler: {
value: TWAP_FALLBACK_HANDLER,
},
},
} as unknown as ReturnType<typeof useSafeInfoHook.default>),
)

const { getByText } = render(<FallbackHandler />)

expect(
getByText(
"This is CoW's fallback handler. It is needed for this Safe to be able to use the TWAP feature for Swaps.",
),
).toBeInTheDocument()
})

it('should not display a message in case it is a TWAP fallback handler on an unsupported network', () => {
jest.spyOn(useSafeInfoHook, 'default').mockImplementation(
() =>
({
safe: {
version: '1.3.0',
chainId: '10',
fallbackHandler: {
value: TWAP_FALLBACK_HANDLER,
},
},
} as unknown as ReturnType<typeof useSafeInfoHook.default>),
)

const { queryByText } = render(<FallbackHandler />)

expect(
queryByText(
"This is CoW's fallback handler. It is needed for this Safe to be able to use the TWAP feature for Swaps.",
),
).not.toBeInTheDocument()
})
})
19 changes: 11 additions & 8 deletions src/components/settings/FallbackHandler/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TWAP_FALLBACK_HANDLER } from '@/features/swap/helpers/utils'
import { TWAP_FALLBACK_HANDLER, TWAP_FALLBACK_HANDLER_NETWORKS } from '@/features/swap/helpers/utils'
import { getCompatibilityFallbackHandlerDeployments } from '@safe-global/safe-deployments'
import NextLink from 'next/link'
import { Typography, Box, Grid, Paper, Link, Alert } from '@mui/material'
import semverSatisfies from 'semver/functions/satisfies'
Expand All @@ -7,7 +8,6 @@ import type { ReactElement } from 'react'

import EthHashInfo from '@/components/common/EthHashInfo'
import useSafeInfo from '@/hooks/useSafeInfo'
import { getFallbackHandlerContractDeployment } from '@/services/contracts/deployments'
import { HelpCenterArticle } from '@/config/constants'
import ExternalLink from '@/components/common/ExternalLink'
import { useTxBuilderApp } from '@/hooks/safe-apps/useTxBuilderApp'
Expand All @@ -22,11 +22,12 @@ export const FallbackHandler = (): ReactElement | null => {

const supportsFallbackHandler = !!safe.version && semverSatisfies(safe.version, FALLBACK_HANDLER_VERSION)

const fallbackHandlerDeployment = useMemo(() => {
if (!chain) {
const fallbackHandlerDeployments = useMemo(() => {
if (!chain || !safe.version) {
return undefined
}
return getFallbackHandlerContractDeployment(chain, safe.version)

return getCompatibilityFallbackHandlerDeployments({ network: chain?.chainId, version: safe.version })
}, [safe.version, chain])

if (!supportsFallbackHandler) {
Expand All @@ -35,8 +36,10 @@ export const FallbackHandler = (): ReactElement | null => {

const hasFallbackHandler = !!safe.fallbackHandler
const isOfficial =
hasFallbackHandler && safe.fallbackHandler?.value === fallbackHandlerDeployment?.networkAddresses[safe.chainId]
const isTWAPFallbackHandler = safe.fallbackHandler?.value === TWAP_FALLBACK_HANDLER
safe.fallbackHandler &&
fallbackHandlerDeployments?.networkAddresses[safe.chainId].includes(safe.fallbackHandler.value)
const isTWAPFallbackHandler =
safe.fallbackHandler?.value === TWAP_FALLBACK_HANDLER && TWAP_FALLBACK_HANDLER_NETWORKS.includes(safe.chainId)

const warning = !hasFallbackHandler ? (
<>
Expand Down Expand Up @@ -101,7 +104,7 @@ export const FallbackHandler = (): ReactElement | null => {
{safe.fallbackHandler && (
<EthHashInfo
shortAddress={false}
name={safe.fallbackHandler.name || fallbackHandlerDeployment?.contractName}
name={safe.fallbackHandler.name || fallbackHandlerDeployments?.contractName}
address={safe.fallbackHandler.value}
customAvatar={safe.fallbackHandler.logoUri}
showCopyButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ export const MigrationToL2TxData = ({ txDetails }: { txDetails: TransactionDetai
}
return createTx({
to: execTxArgs[0],
value: execTxArgs[1],
value: execTxArgs[1].toString(),
data: execTxArgs[2],
operation: execTxArgs[3],
safeTxGas: execTxArgs[4],
baseGas: execTxArgs[5],
gasPrice: execTxArgs[6],
gasToken: execTxArgs[7],
operation: Number(execTxArgs[3]),
safeTxGas: execTxArgs[4].toString(),
baseGas: execTxArgs[5].toString(),
gasPrice: execTxArgs[6].toString(),
gasToken: execTxArgs[7].toString(),
refundReceiver: execTxArgs[8],
})
}
}, [readOnlyProvider, txDetails.txHash, chain, safe.version, sdk])

const [decodedRealTx] = useDecodeTx(realSafeTx)
const [decodedRealTx, decodedRealTxError] = useDecodeTx(realSafeTx)

const decodedDataUnavailable = !realSafeTx && !realSafeTxLoading

Expand All @@ -70,6 +70,8 @@ export const MigrationToL2TxData = ({ txDetails }: { txDetails: TransactionDetai
<MigrateToL2Information variant="history" />
{realSafeTxError ? (
<ErrorMessage>{realSafeTxError.message}</ErrorMessage>
) : decodedRealTxError ? (
<ErrorMessage>{decodedRealTxError.message}</ErrorMessage>
) : decodedDataUnavailable ? (
<DecodedData txData={txDetails.txData} />
) : (
Expand Down
8 changes: 4 additions & 4 deletions src/components/welcome/MyAccounts/AccountItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ const AccountItem = ({ onLinkClick, safeItem }: AccountItemProps) => {
)}
</Typography>

<Typography variant="body2" fontWeight="bold" textAlign="right" pr={5}>
<ChainIndicator chainId={chainId} responsive onlyLogo className={css.chainIndicator} />

<Typography variant="body2" fontWeight="bold" textAlign="right" pl={2}>
{safeOverview ? (
<FiatValue value={safeOverview.fiatTotal} />
) : undeployedSafe ? null : (
<Skeleton variant="text" />
<Skeleton variant="text" sx={{ ml: 'auto' }} />
)}
</Typography>

<ChainIndicator chainId={chainId} responsive />
</Link>
</Track>

Expand Down
12 changes: 6 additions & 6 deletions src/components/welcome/MyAccounts/MultiAccountItem.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { selectUndeployedSafes } from '@/features/counterfactual/store/undeployedSafesSlice'
import NetworkLogosList from '@/features/multichain/components/NetworkLogosList'
import type { SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
import { useCallback, useMemo, useState } from 'react'
import {
Expand All @@ -24,7 +25,6 @@ import classnames from 'classnames'
import { useRouter } from 'next/router'
import FiatValue from '@/components/common/FiatValue'
import { type MultiChainSafeItem } from './useAllSafesGrouped'
import MultiChainIcon from '@/public/images/sidebar/multichain-account.svg'
import { shortenAddress } from '@/utils/formatters'
import { type SafeItem } from './useAllSafes'
import SubAccountItem from './SubAccountItem'
Expand Down Expand Up @@ -58,8 +58,8 @@ const MultichainIndicator = ({ safes }: { safes: SafeItem[] }) => {
}
arrow
>
<Box height="26px">
<MultiChainIcon />
<Box className={css.multiChains}>
<NetworkLogosList networks={safes} showHasMore />
</Box>
</Tooltip>
)
Expand Down Expand Up @@ -143,7 +143,7 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem }: MultiAccountIte
onClick={toggleExpand}
sx={{
pl: 0,
'& .MuiAccordionSummary-content': { m: 0, alignItems: 'center' },
'& .MuiAccordionSummary-content': { m: '0 !important', alignItems: 'center' },
'&.Mui-expanded': { backgroundColor: 'transparent !important' },
}}
>
Expand All @@ -161,14 +161,14 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem }: MultiAccountIte
{shortenAddress(address)}
</Typography>
</Typography>
<Typography variant="body2" fontWeight="bold" textAlign="right" pr={4}>
<MultichainIndicator safes={safes} />
<Typography variant="body2" fontWeight="bold" textAlign="right" pl={2}>
{totalFiatValue !== undefined ? (
<FiatValue value={totalFiatValue} />
) : (
<Skeleton variant="text" sx={{ ml: 'auto' }} />
)}
</Typography>
<MultichainIndicator safes={safes} />
</Box>
<MultiAccountContextMenu name={name ?? ''} address={address} chainIds={deployedChains} />
</AccordionSummary>
Expand Down
2 changes: 1 addition & 1 deletion src/components/welcome/MyAccounts/SubAccountItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const SubAccountItem = ({ onLinkClick, safeItem, safeOverview }: SubAccountItem)
className={classnames(css.listItem, { [css.currentListItem]: isCurrentSafe }, css.subItem)}
>
<Track {...OVERVIEW_EVENTS.OPEN_SAFE} label={trackingLabel}>
<Link onClick={onLinkClick} href={href} className={css.safeLink}>
<Link onClick={onLinkClick} href={href} className={css.safeSubLink}>
<Box pr={2.5}>
<SafeIcon
address={address}
Expand Down
Loading

0 comments on commit cfc732e

Please sign in to comment.