@@ -121,7 +116,6 @@ const SafeHeader = (): ReactElement => {
)
- return isSafenetEnabled ?
{header} : header
}
export default SafeHeader
diff --git a/apps/web/src/features/multichain/components/NetworkLogosList/index.tsx b/apps/web/src/features/multichain/components/NetworkLogosList/index.tsx
index 39c9bd6486..4f363b8ff1 100644
--- a/apps/web/src/features/multichain/components/NetworkLogosList/index.tsx
+++ b/apps/web/src/features/multichain/components/NetworkLogosList/index.tsx
@@ -1,4 +1,5 @@
import ChainIndicator from '@/components/common/ChainIndicator'
+import SafenetIcon from '@/public/images/safenet/safenet-icon.svg'
import { Box } from '@mui/material'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import css from './styles.module.css'
@@ -6,11 +7,13 @@ import css from './styles.module.css'
const NetworkLogosList = ({
networks,
showHasMore = false,
+ showHasSafenet = false,
}: {
networks: Pick
[]
showHasMore?: boolean
+ showHasSafenet?: boolean
}) => {
- const MAX_NUM_VISIBLE_CHAINS = 4
+ const MAX_NUM_VISIBLE_CHAINS = showHasSafenet ? 3 : 4
const visibleChains = showHasMore ? networks.slice(0, MAX_NUM_VISIBLE_CHAINS) : networks
return (
@@ -18,6 +21,11 @@ const NetworkLogosList = ({
{visibleChains.map((chain) => (
))}
+ {showHasSafenet && (
+
+
+
+ )}
{showHasMore && networks.length > MAX_NUM_VISIBLE_CHAINS && (
+{networks.length - MAX_NUM_VISIBLE_CHAINS}
)}
diff --git a/apps/web/src/features/multichain/components/NetworkLogosList/styles.module.css b/apps/web/src/features/multichain/components/NetworkLogosList/styles.module.css
index 136e26c2c0..8343fe78c7 100644
--- a/apps/web/src/features/multichain/components/NetworkLogosList/styles.module.css
+++ b/apps/web/src/features/multichain/components/NetworkLogosList/styles.module.css
@@ -23,3 +23,11 @@
justify-content: center;
font-size: 14px;
}
+
+.safenetIndicator {
+ margin-left: -5px;
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ outline: 2px solid var(--color-background-paper);
+}
diff --git a/apps/web/src/features/myAccounts/components/AccountItems/MultiAccountItem.tsx b/apps/web/src/features/myAccounts/components/AccountItems/MultiAccountItem.tsx
index 217cb1443b..001d855136 100644
--- a/apps/web/src/features/myAccounts/components/AccountItems/MultiAccountItem.tsx
+++ b/apps/web/src/features/myAccounts/components/AccountItems/MultiAccountItem.tsx
@@ -1,82 +1,84 @@
+import ChainIndicator from '@/components/common/ChainIndicator'
+import FiatValue from '@/components/common/FiatValue'
+import SafeIcon from '@/components/common/SafeIcon'
+import MultiAccountContextMenu from '@/components/sidebar/SafeListContextMenu/MultiAccountContextMenu'
+import { AppRoutes } from '@/config/routes'
import { selectUndeployedSafes } from '@/features/counterfactual/store/undeployedSafesSlice'
+import { isPredictedSafeProps } from '@/features/counterfactual/utils'
import NetworkLogosList from '@/features/multichain/components/NetworkLogosList'
-import { showNotification } from '@/store/notificationsSlice'
+import { getSafeSetups, getSharedSetup, hasMultiChainAddNetworkFeature } from '@/features/multichain/utils/utils'
import SingleAccountItem from '@/features/myAccounts/components/AccountItems/SingleAccountItem'
-import type { SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
-import { useCallback, useMemo, useState } from 'react'
+import { type SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
+import { type MultiChainSafeItem } from '@/features/myAccounts/hooks/useAllSafesGrouped'
+import { getComparator } from '@/features/myAccounts/utils/utils'
+import useHasSafenetFeature from '@/features/safenet/hooks/useHasSafenetFeature'
+import useSafeAddress from '@/hooks/useSafeAddress'
+import useWallet from '@/hooks/wallets/useWallet'
+import BookmarkIcon from '@/public/images/apps/bookmark.svg'
+import BookmarkedIcon from '@/public/images/apps/bookmarked.svg'
+import { OVERVIEW_EVENTS, OVERVIEW_LABELS, PIN_SAFE_LABELS, trackEvent } from '@/services/analytics'
+import { useAppDispatch, useAppSelector } from '@/store'
+import { addOrUpdateSafe, pinSafe, selectAllAddedSafes, unpinSafe } from '@/store/addedSafesSlice'
+import { useGetMultipleSafeOverviewsQuery } from '@/store/api/gateway'
+import { selectChains } from '@/store/chainsSlice'
+import { showNotification } from '@/store/notificationsSlice'
+import { selectOrderByPreference } from '@/store/orderByPreferenceSlice'
+import { defaultSafeInfo } from '@/store/safeInfoSlice'
+import { useGetSafenetAccountQuery } from '@/store/safenet'
+import { selectCurrency } from '@/store/settingsSlice'
+import { sameAddress } from '@/utils/addresses'
+import { shortenAddress } from '@/utils/formatters'
import {
- ListItemButton,
- Box,
- Typography,
- Skeleton,
Accordion,
AccordionDetails,
AccordionSummary,
+ Box,
Divider,
- Tooltip,
- SvgIcon,
IconButton,
+ ListItemButton,
+ Skeleton,
+ SvgIcon,
+ Tooltip,
+ Typography,
} from '@mui/material'
-import SafeIcon from '@/components/common/SafeIcon'
-import { OVERVIEW_EVENTS, OVERVIEW_LABELS, PIN_SAFE_LABELS, trackEvent } from '@/services/analytics'
-import { AppRoutes } from '@/config/routes'
-import { useAppDispatch, useAppSelector } from '@/store'
-import css from './styles.module.css'
-import useSafeAddress from '@/hooks/useSafeAddress'
-import { sameAddress } from '@/utils/addresses'
+import type { SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
import classnames from 'classnames'
+import dynamic from 'next/dynamic'
import { useRouter } from 'next/router'
-import FiatValue from '@/components/common/FiatValue'
-import { type MultiChainSafeItem } from '@/features/myAccounts/hooks/useAllSafesGrouped'
-import { shortenAddress } from '@/utils/formatters'
-import { type SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
-import { getSafeSetups, getSharedSetup, hasMultiChainAddNetworkFeature } from '@/features/multichain/utils/utils'
+import { useCallback, useMemo, useState } from 'react'
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'
-import { selectChains } from '@/store/chainsSlice'
-import BookmarkIcon from '@/public/images/apps/bookmark.svg'
-import BookmarkedIcon from '@/public/images/apps/bookmarked.svg'
-import { addOrUpdateSafe, pinSafe, selectAllAddedSafes, unpinSafe } from '@/store/addedSafesSlice'
-import { defaultSafeInfo } from '@/store/safeInfoSlice'
-import { selectOrderByPreference } from '@/store/orderByPreferenceSlice'
-import { getComparator } from '@/features/myAccounts/utils/utils'
-import dynamic from 'next/dynamic'
+import css from './styles.module.css'
-const GradientBoxSafenet = dynamic(() => import('@/features/safenet/components/GradientBoxSafenet'))
+const SafenetMultichainIndicator = dynamic(() => import('@/features/safenet/components/SafenetMultichainIndicator'))
+const SafenetAccountList = dynamic(() => import('@/features/safenet/components/SafenetAccountList'))
type MultiAccountItemProps = {
multiSafeAccountItem: MultiChainSafeItem
safeOverviews?: SafeOverview[]
onLinkClick?: () => void
- isSafenetEnabled?: boolean
+ hasSafenetFeature?: boolean
}
-const MultichainIndicator = ({ safes }: { safes: SafeItem[] }) => {
- return (
-
- Multichain account on:
- {safes.map((safeItem) => (
-
-
-
- ))}
-
- }
- arrow
- >
-
-
+const MultichainIndicator = ({ safes, safenetSafes }: { safes: SafeItem[]; safenetSafes?: SafeItem[] }) => (
+
+ Multichain account on:
+ {safes.map((safeItem) => (
+
+
+
+ ))}
+ {safenetSafes && }
-
- )
-}
+ }
+ arrow
+ >
+
+ 0} />
+
+
+)
function useMultiAccountItemData(multiSafeAccountItem: MultiChainSafeItem) {
const { address, safes, isPinned, name } = multiSafeAccountItem
@@ -127,6 +129,24 @@ function useMultiAccountItemData(multiSafeAccountItem: MultiChainSafeItem) {
const deployedChainIds = useMemo(() => sortedSafes.map((safe) => safe.chainId), [sortedSafes])
+ const hasSafenetFeature = useHasSafenetFeature()
+ const { data: safenetConfig } = useGetSafenetAccountQuery({ safeAddress: address }, { skip: !hasSafenetFeature })
+
+ const nonSafenetSafes = useMemo(() => {
+ if (safenetConfig) {
+ const deployedSafenetChainIds = safenetConfig.safes.map((safe) => safe.chainId.toString())
+ return sortedSafes.filter((safe) => !deployedSafenetChainIds.includes(safe.chainId))
+ }
+ return sortedSafes
+ }, [safenetConfig, sortedSafes])
+
+ const safenetSafes = useMemo(() => {
+ if (safenetConfig) {
+ const deployedSafenetChainIds = safenetConfig.safes.map((safe) => safe.chainId.toString())
+ return sortedSafes.filter((safe) => deployedSafenetChainIds.includes(safe.chainId))
+ }
+ }, [safenetConfig, sortedSafes])
+
return {
address,
name,
@@ -140,6 +160,8 @@ function useMultiAccountItemData(multiSafeAccountItem: MultiChainSafeItem) {
isReadOnly,
isWelcomePage,
deployedChainIds,
+ safenetSafes,
+ nonSafenetSafes,
}
}
@@ -217,7 +239,7 @@ function usePinActions(
return { addToPinnedList, removeFromPinnedList }
}
-const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, isSafenetEnabled }: MultiAccountItemProps) => {
+const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem }: MultiAccountItemProps) => {
const {
address,
name,
@@ -231,6 +253,8 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, isSafenetEnabled
isReadOnly,
isWelcomePage,
deployedChainIds,
+ safenetSafes,
+ nonSafenetSafes,
} = useMultiAccountItemData(multiSafeAccountItem)
const { addToPinnedList, removeFromPinnedList } = usePinActions(address, name, sortedSafes, safeOverviews)
@@ -246,7 +270,7 @@ const MultiAccountItem = ({ onLinkClick, multiSafeAccountItem, isSafenetEnabled
})
}
- const listItem = (
+ return (
-
+
+ {safenetSafes && }
- {sortedSafes.map((safeItem) => (
+ {nonSafenetSafes.map((safeItem) => (
)
- return isSafenetEnabled ? (
- {listItem}
- ) : (
- listItem
- )
}
export default MultiAccountItem
diff --git a/apps/web/src/features/myAccounts/components/AccountItems/SingleAccountItem.tsx b/apps/web/src/features/myAccounts/components/AccountItems/SingleAccountItem.tsx
index f3c5060bb6..8589f82c3b 100644
--- a/apps/web/src/features/myAccounts/components/AccountItems/SingleAccountItem.tsx
+++ b/apps/web/src/features/myAccounts/components/AccountItems/SingleAccountItem.tsx
@@ -1,46 +1,53 @@
-import { selectUndeployedSafe } from '@/features/counterfactual/store/undeployedSafesSlice'
-import { type SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
-import { useMemo, useRef } from 'react'
-import { ListItemButton, Box, Typography, IconButton, SvgIcon, Skeleton, useTheme, useMediaQuery } from '@mui/material'
-import Link from 'next/link'
-import Track from '@/components/common/Track'
-import { OVERVIEW_EVENTS, OVERVIEW_LABELS, PIN_SAFE_LABELS, trackEvent } from '@/services/analytics'
-import { AppRoutes } from '@/config/routes'
-import { useAppDispatch, useAppSelector } from '@/store'
-import { selectChainById } from '@/store/chainsSlice'
import ChainIndicator from '@/components/common/ChainIndicator'
-import css from './styles.module.css'
-import { selectAllAddressBooks } from '@/store/addressBookSlice'
-import { shortenAddress } from '@/utils/formatters'
+import FiatValue from '@/components/common/FiatValue'
+import SafeIcon from '@/components/common/SafeIcon'
+import Track from '@/components/common/Track'
import SafeListContextMenu from '@/components/sidebar/SafeListContextMenu'
-import useSafeAddress from '@/hooks/useSafeAddress'
-import useChainId from '@/hooks/useChainId'
-import { sameAddress } from '@/utils/addresses'
-import classnames from 'classnames'
-import { useRouter } from 'next/router'
+import { AppRoutes } from '@/config/routes'
+import { selectUndeployedSafe } from '@/features/counterfactual/store/undeployedSafesSlice'
+import { extractCounterfactualSafeSetup, isPredictedSafeProps } from '@/features/counterfactual/utils'
+import { hasMultiChainAddNetworkFeature } from '@/features/multichain/utils/utils'
import type { SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
import { useGetHref } from '@/features/myAccounts/hooks/useGetHref'
-import { extractCounterfactualSafeSetup, isPredictedSafeProps } from '@/features/counterfactual/utils'
+import SafenetTag from '@/features/safenet/components/SafenetTag'
+import useChainId from '@/hooks/useChainId'
+import useOnceVisible from '@/hooks/useOnceVisible'
+import useSafeAddress from '@/hooks/useSafeAddress'
import useWallet from '@/hooks/wallets/useWallet'
-import { hasMultiChainAddNetworkFeature } from '@/features/multichain/utils/utils'
import BookmarkIcon from '@/public/images/apps/bookmark.svg'
import BookmarkedIcon from '@/public/images/apps/bookmarked.svg'
+import { OVERVIEW_EVENTS, OVERVIEW_LABELS, PIN_SAFE_LABELS, trackEvent } from '@/services/analytics'
+import { useAppDispatch, useAppSelector } from '@/store'
import { addOrUpdateSafe, unpinSafe } from '@/store/addedSafesSlice'
-import SafeIcon from '@/components/common/SafeIcon'
-import useOnceVisible from '@/hooks/useOnceVisible'
-import { skipToken } from '@reduxjs/toolkit/query'
+import { selectAllAddressBooks } from '@/store/addressBookSlice'
+import { selectChainById } from '@/store/chainsSlice'
import { defaultSafeInfo, showNotification, useGetSafeOverviewQuery } from '@/store/slices'
-import FiatValue from '@/components/common/FiatValue'
+import { sameAddress } from '@/utils/addresses'
+import { shortenAddress } from '@/utils/formatters'
+import { Box, IconButton, ListItemButton, Skeleton, SvgIcon, Typography, useMediaQuery, useTheme } from '@mui/material'
+import { skipToken } from '@reduxjs/toolkit/query'
+import { type SafeOverview } from '@safe-global/safe-gateway-typescript-sdk'
+import classnames from 'classnames'
+import Link from 'next/link'
+import { useRouter } from 'next/router'
+import { useMemo, useRef } from 'react'
import { AccountInfoChips } from '../AccountInfoChips'
+import css from './styles.module.css'
type AccountItemProps = {
safeItem: SafeItem
safeOverview?: SafeOverview
onLinkClick?: () => void
isMultiChainItem?: boolean
+ isSafenetItem?: boolean
}
-const SingleAccountItem = ({ onLinkClick, safeItem, isMultiChainItem = false }: AccountItemProps) => {
+const SingleAccountItem = ({
+ onLinkClick,
+ safeItem,
+ isMultiChainItem = false,
+ isSafenetItem = false,
+}: AccountItemProps) => {
const { chainId, address, isReadOnly, isPinned } = safeItem
const chain = useAppSelector((state) => selectChainById(state, chainId))
const undeployedSafe = useAppSelector((state) => selectUndeployedSafe(state, chainId, address))
@@ -208,6 +215,8 @@ const SingleAccountItem = ({ onLinkClick, safeItem, isMultiChainItem = false }:
{!isMultiChainItem && }
+ {isSafenetItem && }
+
{undeployedSafe ? null : safeOverview ? (
diff --git a/apps/web/src/features/myAccounts/components/AccountItems/styles.module.css b/apps/web/src/features/myAccounts/components/AccountItems/styles.module.css
index 838c2b46f2..03268c8e53 100644
--- a/apps/web/src/features/myAccounts/components/AccountItems/styles.module.css
+++ b/apps/web/src/features/myAccounts/components/AccountItems/styles.module.css
@@ -141,13 +141,3 @@
justify-content: flex-start;
}
}
-
-.safenetListItem {
- margin-bottom: 12px;
-}
-
-.safenetListItem .listItem {
- border: none;
- border-radius-left-top: 0;
- border-radius-right-top: 0;
-}
diff --git a/apps/web/src/features/myAccounts/components/SafesList/index.tsx b/apps/web/src/features/myAccounts/components/SafesList/index.tsx
index cedf285839..07501e8cfb 100644
--- a/apps/web/src/features/myAccounts/components/SafesList/index.tsx
+++ b/apps/web/src/features/myAccounts/components/SafesList/index.tsx
@@ -3,7 +3,6 @@ import MultiAccountItem from '@/features/myAccounts/components/AccountItems/Mult
import SingleAccountItem from '@/features/myAccounts/components/AccountItems/SingleAccountItem'
import type { SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
import type { MultiChainSafeItem } from '@/features/myAccounts/hooks/useAllSafesGrouped'
-import useHasSafenetFeature from '@/features/safenet/hooks/useHasSafenetFeature'
import { Collapse } from '@mui/material'
import { TransitionGroup } from 'react-transition-group'
@@ -13,17 +12,15 @@ type SafeListProps = {
useTransitions?: boolean
}
-const renderSafeItem = (item: SafeItem | MultiChainSafeItem, onLinkClick?: () => void, hasSafenetFeature?: boolean) => {
+const renderSafeItem = (item: SafeItem | MultiChainSafeItem, onLinkClick?: () => void) => {
return isMultiChainSafeItem(item) ? (
-
+
) : (
)
}
const SafesList = ({ safes, onLinkClick, useTransitions = true }: SafeListProps) => {
- const hasSafenetFeature = useHasSafenetFeature()
-
if (!safes || safes.length === 0) {
return null
}
@@ -32,14 +29,14 @@ const SafesList = ({ safes, onLinkClick, useTransitions = true }: SafeListProps)
{safes.map((item) => (
- {renderSafeItem(item, onLinkClick, hasSafenetFeature)}
+ {renderSafeItem(item, onLinkClick)}
))}
) : (
<>
{safes.map((item) => (
- {renderSafeItem(item, onLinkClick, hasSafenetFeature)}
+ {renderSafeItem(item, onLinkClick)}
))}
>
)
diff --git a/apps/web/src/features/safenet/components/GradientBoxSafenet/index.tsx b/apps/web/src/features/safenet/components/GradientBoxSafenet/index.tsx
deleted file mode 100644
index 9a949a8dc2..0000000000
--- a/apps/web/src/features/safenet/components/GradientBoxSafenet/index.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import SafenetIcon from '@/public/images/safenet/safenet.svg'
-import { Box, SvgIcon, Typography } from '@mui/material'
-import { type CSSProperties, type ReactNode } from 'react'
-
-const GradientBoxSafenet = ({
- heading,
- children,
- className,
- style,
- variant = 'full',
-}: {
- heading?: string
- children?: ReactNode
- className?: string
- style?: CSSProperties
- variant?: 'full' | 'bottom'
-}) => {
- const br = 'calc(var(--space-1) - 1px)'
- return (
-
- {variant === 'full' && (
-
-
-
- {heading ?? 'Powered by Safenet'}
-
-
- )}
-
- {children}
-
-
- )
-}
-
-export default GradientBoxSafenet
diff --git a/apps/web/src/features/safenet/components/SafenetAccountList/index.tsx b/apps/web/src/features/safenet/components/SafenetAccountList/index.tsx
new file mode 100644
index 0000000000..160e7a4ae7
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetAccountList/index.tsx
@@ -0,0 +1,30 @@
+import SingleAccountItem from '@/features/myAccounts/components/AccountItems/SingleAccountItem'
+import type { SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
+import { useDarkMode } from '@/hooks/useDarkMode'
+import SafenetDarkLogo from '@/public/images/safenet/logo-safenet-dark-gradient.svg'
+import SafenetLogo from '@/public/images/safenet/logo-safenet.svg'
+import { Box } from '@mui/material'
+import css from './styles.module.css'
+
+const SafenetAccountList = ({ safenetSafes, onLinkClick }: { safenetSafes: SafeItem[]; onLinkClick?: () => void }) => {
+ const isDarkMode = useDarkMode()
+
+ return safenetSafes.length > 0 ? (
+
+
+ {isDarkMode ? : }
+
+ {safenetSafes.map((safeItem) => (
+
+ ))}
+
+ ) : undefined
+}
+
+export default SafenetAccountList
diff --git a/apps/web/src/features/safenet/components/SafenetAccountList/styles.module.css b/apps/web/src/features/safenet/components/SafenetAccountList/styles.module.css
new file mode 100644
index 0000000000..365d2fc13d
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetAccountList/styles.module.css
@@ -0,0 +1,21 @@
+.safenetList {
+ border: 1px solid var(--color-border-light);
+ border-radius: var(--space-1);
+ margin-bottom: 12px;
+ flex-wrap: wrap;
+ overflow: hidden;
+}
+
+.safenetList > div {
+ border: none;
+ border-top: 1px solid var(--color-border-light);
+ border-radius: 0;
+ margin-bottom: 0;
+ flex-wrap: wrap;
+}
+
+.safenetList > .safenetListHeader {
+ border: none;
+ background: var(--color-background-main);
+ padding: 4px var(--space-2);
+}
diff --git a/apps/web/src/features/safenet/components/SafenetMultichainIndicator/index.tsx b/apps/web/src/features/safenet/components/SafenetMultichainIndicator/index.tsx
new file mode 100644
index 0000000000..221bbbeb96
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetMultichainIndicator/index.tsx
@@ -0,0 +1,27 @@
+import ChainIndicator from '@/components/common/ChainIndicator'
+import type { SafeItem } from '@/features/myAccounts/hooks/useAllSafes'
+import { useDarkMode } from '@/hooks/useDarkMode'
+import SafenetDarkLogo from '@/public/images/safenet/logo-safenet-dark-gradient.svg'
+import SafenetLightLogo from '@/public/images/safenet/logo-safenet-light-gradient.svg'
+import { Box, Divider } from '@mui/material'
+import css from './styles.module.css'
+
+const SafenetMultichainIndicator = ({ safenetSafes }: { safenetSafes: SafeItem[] }) => {
+ const isDarkMode = useDarkMode()
+
+ return safenetSafes.length > 0 ? (
+
+
+
+ {isDarkMode ? : }
+
+ {safenetSafes.map((safeItem) => (
+
+
+
+ ))}
+
+ ) : undefined
+}
+
+export default SafenetMultichainIndicator
diff --git a/apps/web/src/features/safenet/components/SafenetMultichainIndicator/styles.module.css b/apps/web/src/features/safenet/components/SafenetMultichainIndicator/styles.module.css
new file mode 100644
index 0000000000..3acb1a0365
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetMultichainIndicator/styles.module.css
@@ -0,0 +1,21 @@
+.safenetTooltip {
+ position: relative;
+}
+
+.safenetLogo {
+ position: absolute;
+ top: -6px;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+.safenetLogo > svg {
+ background: var(--color-text-primary);
+ padding: 0 var(--space-2);
+}
+
+.divider {
+ margin: 16px -8px;
+ border-color: var(--color-border-main);
+}
diff --git a/apps/web/src/features/safenet/components/SafenetSidebarHeader/index.tsx b/apps/web/src/features/safenet/components/SafenetSidebarHeader/index.tsx
new file mode 100644
index 0000000000..41aa99ae3f
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetSidebarHeader/index.tsx
@@ -0,0 +1,12 @@
+import SafenetDarkLogo from '@/public/images/safenet/logo-safenet-dark-gradient.svg'
+import { Box } from '@mui/material'
+import type { ReactElement } from 'react'
+import css from './styles.module.css'
+
+const SafenetSidebarHeader = (): ReactElement => (
+
+
+
+)
+
+export default SafenetSidebarHeader
diff --git a/apps/web/src/features/safenet/components/SafenetSidebarHeader/styles.module.css b/apps/web/src/features/safenet/components/SafenetSidebarHeader/styles.module.css
new file mode 100644
index 0000000000..011b015fa4
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetSidebarHeader/styles.module.css
@@ -0,0 +1,9 @@
+.safenetHeader {
+ background: linear-gradient(269.61deg, #FF5F00 -34.26%, #FFD200 32.94%, #12FF80 92.29%);
+ border-radius: 0 0 var(--space-1) var(--space-1);
+ padding: var(--space-1);
+}
+
+.safenetHeader > svg {
+ display: block;
+}
diff --git a/apps/web/src/features/safenet/components/SafenetTag/index.tsx b/apps/web/src/features/safenet/components/SafenetTag/index.tsx
new file mode 100644
index 0000000000..f0183d2103
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetTag/index.tsx
@@ -0,0 +1,14 @@
+import { useDarkMode } from '@/hooks/useDarkMode'
+import SafenetDarkLogo from '@/public/images/safenet/logo-safenet-dark-gradient.svg'
+import SafenetLogo from '@/public/images/safenet/logo-safenet.svg'
+import { Box } from '@mui/material'
+import type { ReactElement } from 'react'
+import css from './styles.module.css'
+
+const SafenetTag = (): ReactElement => {
+ const isDarkMode = useDarkMode()
+
+ return {isDarkMode ? : }
+}
+
+export default SafenetTag
diff --git a/apps/web/src/features/safenet/components/SafenetTag/styles.module.css b/apps/web/src/features/safenet/components/SafenetTag/styles.module.css
new file mode 100644
index 0000000000..6f8457019c
--- /dev/null
+++ b/apps/web/src/features/safenet/components/SafenetTag/styles.module.css
@@ -0,0 +1,13 @@
+.tag {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: var(--space-1);
+ padding: 6px 8px;
+ border: 1px solid transparent;
+ border-radius: 20px;
+ background-image: radial-gradient(var(--color-secondary-background) 0%, var(--color-secondary-background) 100%),
+ radial-gradient(119.01% 132.63% at 119.01% -14.15%, #ff5f00 0%, #ffd200 50%, #12ff80 100%);
+ background-origin: border-box;
+ background-clip: padding-box, border-box;
+}
diff --git a/apps/web/src/store/safenet.ts b/apps/web/src/store/safenet.ts
index def21f90b6..3806f2f9b1 100644
--- a/apps/web/src/store/safenet.ts
+++ b/apps/web/src/store/safenet.ts
@@ -4,12 +4,6 @@ import { type RequiredTenderlySimulation } from '@/components/tx/security/tender
import { SAFENET_API_URL } from '@/config/constants'
import type { SafeVersion } from '@safe-global/safe-core-sdk-types'
-export type SafenetSafeEntity = {
- safe: string
- chainId: number
- guard: string
-}
-
export type SafenetConfigEntity = {
chains: number[]
guards: Record
@@ -18,6 +12,20 @@ export type SafenetConfigEntity = {
processors: Record
}
+export type SafenetAccountEntity = {
+ guarantees: {
+ guarantee: string
+ inactiveAfter: string
+ activeAfter: string
+ }[]
+ handle: string
+ safes: {
+ address: string
+ chainId: number
+ guard: string
+ }[]
+}
+
export type SafenetBalanceEntity = {
[tokenSymbol: string]: string
}
@@ -56,7 +64,7 @@ export const getSafenetBalances = async (safeAddress: string): Promise ({
getSafenetConfig: builder.query({
query: () => ({
@@ -67,9 +75,9 @@ export const safenetApi = createApi({
}),
providesTags: ['SafenetConfig'],
}),
- getSafenetOffchainStatus: builder.query({
- query: ({ chainId, safeAddress }) => `/account/${chainId}/${safeAddress}`,
- providesTags: (_, __, arg) => [{ type: 'SafenetOffchainStatus', id: arg.safeAddress }],
+ getSafenetAccount: builder.query({
+ query: ({ safeAddress }) => `/account/${safeAddress}`,
+ providesTags: (_, __, arg) => [{ type: 'SafenetAccount', id: arg.safeAddress }],
}),
registerSafenet: builder.mutation({
query: ({ chainId, safeAddress }) => ({
@@ -80,7 +88,7 @@ export const safenetApi = createApi({
safe: safeAddress,
},
}),
- invalidatesTags: (_, __, arg) => [{ type: 'SafenetOffchainStatus', id: arg.safeAddress }],
+ invalidatesTags: (_, __, arg) => [{ type: 'SafenetAccount', id: arg.safeAddress }],
}),
getSafenetBalance: builder.query({
query: ({ safeAddress }) => `/balances/${safeAddress}`,
@@ -122,6 +130,7 @@ export const safenetApi = createApi({
export const {
useGetSafenetConfigQuery,
+ useGetSafenetAccountQuery,
useLazyGetSafenetBalanceQuery,
useLazySimulateSafenetTransactionQuery,
useLazyDeploySafenetAccountQuery,