Commit 4d3ce52b authored by Max Alekseenko's avatar Max Alekseenko

add security score to dapp page

parent e2c79df7
import { Box, Text, Link } from '@chakra-ui/react'; import { Box, Text, Link } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { ContractListTypes } from 'types/client/marketplace';
import config from 'configs/app'; import config from 'configs/app';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -11,13 +9,16 @@ import SolidityscanReportDetails from 'ui/shared/solidityscanReport/Solidityscan ...@@ -11,13 +9,16 @@ import SolidityscanReportDetails from 'ui/shared/solidityscanReport/Solidityscan
import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanReportScore'; import SolidityscanReportScore from 'ui/shared/solidityscanReport/SolidityscanReportScore';
type Props = { type Props = {
id: string;
securityReport?: any; // eslint-disable-line @typescript-eslint/no-explicit-any securityReport?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
height?: string | undefined; height?: string | undefined;
showContractList: (id: string, type: ContractListTypes) => void; showContractList: () => void;
} }
const AppSecurityReport = ({ id, securityReport, height, showContractList }: Props) => { const AppSecurityReport = ({ securityReport, height, showContractList }: Props) => {
if (!securityReport) {
return null;
}
const { const {
overallInfo: { overallInfo: {
securityScore, securityScore,
...@@ -27,11 +28,6 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList }: Pro ...@@ -27,11 +28,6 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList }: Pro
}, },
} = securityReport; } = securityReport;
const showAnalyzedContracts = React.useCallback(() => {
showContractList(id, ContractListTypes.ANALYZED);
}, [ showContractList, id ]);
return ( return (
<SolidityscanReportButton <SolidityscanReportButton
height={ height } height={ height }
...@@ -49,7 +45,7 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList }: Pro ...@@ -49,7 +45,7 @@ const AppSecurityReport = ({ id, securityReport, height, showContractList }: Pro
<SolidityscanReportDetails vulnerabilities={ issueSeverityDistribution } vulnerabilitiesCount={ totalIssues }/> <SolidityscanReportDetails vulnerabilities={ issueSeverityDistribution } vulnerabilitiesCount={ totalIssues }/>
</Box> </Box>
) } ) }
<Link onClick={ showAnalyzedContracts } display="inline-flex" alignItems="center"> <Link onClick={ showContractList } display="inline-flex" alignItems="center">
Analyzed contracts Analyzed contracts
<IconSvg name="arrows/north-east" boxSize={ 5 } color="gray.400"/> <IconSvg name="arrows/north-east" boxSize={ 5 } color="gray.400"/>
</Link> </Link>
......
...@@ -68,21 +68,25 @@ const MarketplaceAppModal = ({ ...@@ -68,21 +68,25 @@ const MarketplaceAppModal = ({
} }
const handleFavoriteClick = useCallback(() => { const handleFavoriteClick = useCallback(() => {
onFavoriteClick(data.id, isFavorite); onFavoriteClick(id, isFavorite);
}, [ onFavoriteClick, data.id, isFavorite ]); }, [ onFavoriteClick, id, isFavorite ]);
const showContractList = useCallback((id: string, type: ContractListTypes) => { const showContractList = useCallback((type: ContractListTypes) => {
onClose(); onClose();
showContractListDefault(id, type); showContractListDefault(id, type);
}, [ onClose, showContractListDefault ]); }, [ onClose, showContractListDefault, id ]);
const showAllContracts = React.useCallback(() => { const showAllContracts = React.useCallback(() => {
showContractList(id, ContractListTypes.ALL); showContractList(ContractListTypes.ALL);
}, [ showContractList, id ]); }, [ showContractList ]);
const showVerifiedContracts = React.useCallback(() => { const showVerifiedContracts = React.useCallback(() => {
showContractList(id, ContractListTypes.VERIFIED); showContractList(ContractListTypes.VERIFIED);
}, [ showContractList, id ]); }, [ showContractList ]);
const showAnalyzedContracts = React.useCallback(() => {
showContractList(ContractListTypes.ANALYZED);
}, [ showContractList ]);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const logoUrl = useColorModeValue(logo, logoDarkMode || logo); const logoUrl = useColorModeValue(logo, logoDarkMode || logo);
...@@ -167,7 +171,7 @@ const MarketplaceAppModal = ({ ...@@ -167,7 +171,7 @@ const MarketplaceAppModal = ({
{ securityReport && ( { securityReport && (
<Flex alignItems="center" gap={ 3 }> <Flex alignItems="center" gap={ 3 }>
<AppSecurityReport id={ data.id } securityReport={ securityReport } showContractList={ showContractList }/> <AppSecurityReport securityReport={ securityReport } showContractList={ showAnalyzedContracts }/>
<ContractListButton <ContractListButton
onClick={ showAllContracts } onClick={ showAllContracts }
variant={ ContractListButtonVariants.ALL_CONTRACTS } variant={ ContractListButtonVariants.ALL_CONTRACTS }
......
import { chakra, Flex, Tooltip, Skeleton } from '@chakra-ui/react'; import { chakra, Flex, Tooltip, Skeleton, useBoolean } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { MarketplaceAppOverview } from 'types/client/marketplace'; import type { MarketplaceAppOverview } from 'types/client/marketplace';
import { ContractListTypes } from 'types/client/marketplace';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
...@@ -10,6 +11,8 @@ import IconSvg from 'ui/shared/IconSvg'; ...@@ -10,6 +11,8 @@ import IconSvg from 'ui/shared/IconSvg';
import LinkExternal from 'ui/shared/LinkExternal'; import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
import AppSecurityReport from './AppSecurityReport';
import ContractListModal from './ContractListModal';
import MarketplaceAppAlert from './MarketplaceAppAlert'; import MarketplaceAppAlert from './MarketplaceAppAlert';
import MarketplaceAppInfo from './MarketplaceAppInfo'; import MarketplaceAppInfo from './MarketplaceAppInfo';
...@@ -17,9 +20,11 @@ type Props = { ...@@ -17,9 +20,11 @@ type Props = {
data: MarketplaceAppOverview | undefined; data: MarketplaceAppOverview | undefined;
isLoading: boolean; isLoading: boolean;
isWalletConnected: boolean; isWalletConnected: boolean;
securityReport?: any; // eslint-disable-line @typescript-eslint/no-explicit-any
} }
const MarketplaceAppTopBar = ({ data, isLoading, isWalletConnected }: Props) => { const MarketplaceAppTopBar = ({ data, isLoading, isWalletConnected, securityReport }: Props) => {
const [ showContractList, setShowContractList ] = useBoolean(false);
const appProps = useAppContext(); const appProps = useAppContext();
const goBackUrl = React.useMemo(() => { const goBackUrl = React.useMemo(() => {
...@@ -36,34 +41,46 @@ const MarketplaceAppTopBar = ({ data, isLoading, isWalletConnected }: Props) => ...@@ -36,34 +41,46 @@ const MarketplaceAppTopBar = ({ data, isLoading, isWalletConnected }: Props) =>
} }
return ( return (
<Flex alignItems="center" flexWrap="wrap" mb={{ base: 6, md: 2 }} rowGap={ 3 } columnGap={ 2 }> <>
<Tooltip label="Back to dApps list" order={ 1 }> <Flex alignItems="center" flexWrap="wrap" mb={{ base: 6, md: 2 }} rowGap={ 3 } columnGap={ 2 }>
<LinkInternal display="inline-flex" href={ goBackUrl } h="32px" isLoading={ isLoading }> <Tooltip label="Back to dApps list" order={ 1 }>
<IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400"/> <LinkInternal display="inline-flex" href={ goBackUrl } h="32px" isLoading={ isLoading }>
</LinkInternal> <IconSvg name="arrows/east" boxSize={ 6 } transform="rotate(180deg)" margin="auto" color="gray.400"/>
</Tooltip> </LinkInternal>
<Skeleton width={{ base: '100%', md: 'auto' }} order={{ base: 4, md: 2 }} isLoaded={ !isLoading }> </Tooltip>
<MarketplaceAppAlert internalWallet={ data?.internalWallet } isWalletConnected={ isWalletConnected }/> <Skeleton width={{ base: '100%', md: 'auto' }} order={{ base: 4, md: 2 }} isLoaded={ !isLoading }>
</Skeleton> <MarketplaceAppAlert internalWallet={ data?.internalWallet } isWalletConnected={ isWalletConnected }/>
<Skeleton order={{ base: 2, md: 3 }} isLoaded={ !isLoading }> </Skeleton>
<MarketplaceAppInfo data={ data }/> <Skeleton order={{ base: 2, md: 3 }} isLoaded={ !isLoading }>
</Skeleton> <MarketplaceAppInfo data={ data }/>
<LinkExternal </Skeleton>
order={{ base: 3, md: 4 }} <Skeleton order={{ base: 2, md: 3 }} isLoaded={ !isLoading }>
href={ data?.url } <AppSecurityReport securityReport={ securityReport } showContractList={ setShowContractList.on }/>
variant="subtle" </Skeleton>
fontSize="sm" <LinkExternal
lineHeight={ 5 } order={{ base: 3, md: 4 }}
minW={ 0 } href={ data?.url }
maxW={{ base: 'calc(100% - 114px)', md: 'auto' }} variant="subtle"
display="flex" fontSize="sm"
isLoading={ isLoading } lineHeight={ 5 }
> minW={ 0 }
<chakra.span isTruncated> maxW={{ base: 'calc(100% - 114px)', md: 'auto' }}
{ getHostname(data?.url) } display="flex"
</chakra.span> isLoading={ isLoading }
</LinkExternal> >
</Flex> <chakra.span isTruncated>
{ getHostname(data?.url) }
</chakra.span>
</LinkExternal>
</Flex>
{ showContractList && (
<ContractListModal
type={ ContractListTypes.ANALYZED }
contracts={ securityReport?.contractsData }
onClose={ setShowContractList.off }
/>
) }
</>
); );
}; };
......
...@@ -45,6 +45,10 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on ...@@ -45,6 +45,10 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on
showContractList(id, ContractListTypes.VERIFIED); showContractList(id, ContractListTypes.VERIFIED);
}, [ showContractList, id ]); }, [ showContractList, id ]);
const showAnalyzedContracts = React.useCallback(() => {
showContractList(id, ContractListTypes.ANALYZED);
}, [ showContractList, id ]);
return ( return (
<ListItemMobile <ListItemMobile
rowGap={ 3 } rowGap={ 3 }
...@@ -92,9 +96,8 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on ...@@ -92,9 +96,8 @@ const ListItem = ({ app, onInfoClick, isFavorite, onFavoriteClick, isLoading, on
{ securityReport ? ( { securityReport ? (
<> <>
<AppSecurityReport <AppSecurityReport
id={ id }
securityReport={ securityReport } securityReport={ securityReport }
showContractList={ showContractList } showContractList={ showAnalyzedContracts }
height="30px" height="30px"
/> />
<ContractListButton onClick={ showAllContracts } variant={ ContractListButtonVariants.ALL_CONTRACTS }> <ContractListButton onClick={ showAllContracts } variant={ ContractListButtonVariants.ALL_CONTRACTS }>
......
...@@ -54,6 +54,10 @@ const TableItem = ({ ...@@ -54,6 +54,10 @@ const TableItem = ({
showContractList(id, ContractListTypes.VERIFIED); showContractList(id, ContractListTypes.VERIFIED);
}, [ showContractList, id ]); }, [ showContractList, id ]);
const showAnalyzedContracts = React.useCallback(() => {
showContractList(id, ContractListTypes.ANALYZED);
}, [ showContractList, id ]);
return ( return (
<Tr> <Tr>
<Td verticalAlign="middle" px={ 2 }> <Td verticalAlign="middle" px={ 2 }>
...@@ -76,7 +80,7 @@ const TableItem = ({ ...@@ -76,7 +80,7 @@ const TableItem = ({
</Td> </Td>
<Td verticalAlign="middle"> <Td verticalAlign="middle">
{ securityReport ? ( { securityReport ? (
<AppSecurityReport id={ id } securityReport={ securityReport } showContractList={ showContractList }/> <AppSecurityReport securityReport={ securityReport } showContractList={ showAnalyzedContracts }/>
) : ( ) : (
<DataNotAvailable/> <DataNotAvailable/>
) } ) }
......
...@@ -20,6 +20,7 @@ import ContentLoader from 'ui/shared/ContentLoader'; ...@@ -20,6 +20,7 @@ import ContentLoader from 'ui/shared/ContentLoader';
import MarketplaceAppTopBar from '../marketplace/MarketplaceAppTopBar'; import MarketplaceAppTopBar from '../marketplace/MarketplaceAppTopBar';
import useAutoConnectWallet from '../marketplace/useAutoConnectWallet'; import useAutoConnectWallet from '../marketplace/useAutoConnectWallet';
import useMarketplaceWallet from '../marketplace/useMarketplaceWallet'; import useMarketplaceWallet from '../marketplace/useMarketplaceWallet';
import useSecurityReports from '../marketplace/useSecurityReports';
const feature = config.features.marketplace; const feature = config.features.marketplace;
...@@ -104,6 +105,9 @@ const MarketplaceApp = () => { ...@@ -104,6 +105,9 @@ const MarketplaceApp = () => {
const { address, sendTransaction, signMessage, signTypedData } = useMarketplaceWallet(id); const { address, sendTransaction, signMessage, signTypedData } = useMarketplaceWallet(id);
useAutoConnectWallet(); useAutoConnectWallet();
const { data: securityReports, isPending: isSecurityReportsPending } = useSecurityReports();
const securityReport = securityReports?.find(item => item.appName === id)?.chainsData[config.chain.id || ''];
const query = useQuery<unknown, ResourceError<unknown>, MarketplaceAppOverview>({ const query = useQuery<unknown, ResourceError<unknown>, MarketplaceAppOverview>({
queryKey: [ 'marketplace-dapps', id ], queryKey: [ 'marketplace-dapps', id ],
queryFn: async() => { queryFn: async() => {
...@@ -140,7 +144,12 @@ const MarketplaceApp = () => { ...@@ -140,7 +144,12 @@ const MarketplaceApp = () => {
return ( return (
<> <>
<MarketplaceAppTopBar data={ data } isLoading={ isPending } isWalletConnected={ Boolean(address) }/> <MarketplaceAppTopBar
data={ data }
isLoading={ isPending || isSecurityReportsPending }
isWalletConnected={ Boolean(address) }
securityReport={ securityReport }
/>
<DappscoutIframeProvider <DappscoutIframeProvider
address={ address } address={ address }
appUrl={ data?.url } appUrl={ data?.url }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment