Commit b26c40e4 authored by tom's avatar tom

more snippets and alerts

parent 455ac4bb
...@@ -12,13 +12,37 @@ export interface SmartContract { ...@@ -12,13 +12,37 @@ export interface SmartContract {
name: string | null; name: string | null;
verified_at: string | null; verified_at: string | null;
is_verified: boolean | null; is_verified: boolean | null;
is_changed_bytecode: boolean | null;
// sourcify info >>>
is_verified_via_sourcify: boolean | null;
is_fully_verified: boolean | null;
is_partially_verified: boolean | null;
sourcify_repo_url: string | null;
// <<<<
source_code: string | null; source_code: string | null;
constructor_args: string | null; constructor_args: string | null;
decoded_constructor_args: Array<SmartContractDecodedConstructorArg> | null;
can_be_visualized_via_sol2uml: boolean | null; can_be_visualized_via_sol2uml: boolean | null;
is_vyper_contract: boolean | null; is_vyper_contract: boolean | null;
file_path: string; file_path: string;
additional_sources: Array<{ file_path: string; source_code: string }>; additional_sources: Array<{ file_path: string; source_code: string }>;
external_libraries: Array<SmartContractExternalLibrary> | null;
compiler_settings: unknown; compiler_settings: unknown;
verified_twin_address_hash: string | null;
}
export type SmartContractDecodedConstructorArg = [
string,
{
internalType: string;
name: string;
type: string;
}
]
export interface SmartContractExternalLibrary {
address_hash: string;
name: string;
} }
export interface SmartContractMethodBase { export interface SmartContractMethodBase {
......
import { Flex, Skeleton, Button, Grid, GridItem, Text, Alert, Link, chakra } from '@chakra-ui/react'; import { Flex, Skeleton, Button, Grid, GridItem, Text, Alert, Link, chakra, Box } from '@chakra-ui/react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -69,27 +69,71 @@ const ContractCode = () => { ...@@ -69,27 +69,71 @@ const ContractCode = () => {
</Button> </Button>
); );
const constructorArgs = (() => {
if (!data.decoded_constructor_args) {
return data.constructor_args;
}
const decoded = data.decoded_constructor_args
.map(([ value, { name, type } ], index) => {
const valueEl = type === 'address' ? <Link href={ link('address_index', { id: value }) }>{ value }</Link> : <span>{ value }</span>;
return (
<Box key={ index }>
<span>Arg [{ index }] { name || '' } ({ type }): </span>
{ valueEl }
</Box>
);
});
return (
<>
<span>{ data.constructor_args }</span>
<br/><br/>
{ decoded }
</>
);
})();
const externalLibraries = (() => {
if (!data.external_libraries || data.external_libraries.length === 0) {
return null;
}
return data.external_libraries.map((item) => (
<Box key={ item.address_hash }>
<chakra.span fontWeight={ 500 }>{ item.name }: </chakra.span>
<Link href={ link('address_index', { id: item.address_hash }, { tab: 'contract' }) }>{ item.address_hash }</Link>
</Box>
));
})();
return ( return (
<> <>
<Flex flexDir="column" rowGap={ 2 } mb={ 6 }> <Flex flexDir="column" rowGap={ 2 } mb={ 6 } _empty={{ display: 'none' }}>
<Alert status="success">Contract Source Code Verified (Exact Match)</Alert> { data.is_verified && <Alert status="success">Contract Source Code Verified (Exact Match)</Alert> }
<Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap"> { data.is_verified_via_sourcify && (
<span>This contract has been partially verified via Sourcify. </span> <Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap">
<ExternalLink href="https://repo.sourcify.dev/" title="View contract in Sourcify repository" fontSize="md"/> <span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified via Sourcify. </span>
</Alert> { data.sourcify_repo_url && <ExternalLink href={ data.sourcify_repo_url } title="View contract in Sourcify repository" fontSize="md"/> }
<Alert status="warning"> </Alert>
Warning! Contract bytecode has been changed and does not match the verified one. Therefore, interaction with this smart contract may be risky. ) }
</Alert> { data.is_changed_bytecode && (
<Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap"> <Alert status="warning">
<span>Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB </span> Warning! Contract bytecode has been changed and does not match the verified one. Therefore, interaction with this smart contract may be risky.
<Address> </Alert>
<AddressIcon address={{ hash: addressHash || '', is_contract: false, implementation_name: null }}/> ) }
<AddressLink hash={ addressHash || '' } truncation="constant" ml={ 2 }/> { !data.is_verified && data.verified_twin_address_hash && (
</Address> <Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap">
<chakra.span mt={ 1 }>All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with </chakra.span> <span>Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB </span>
<Link>Verify & Publish</Link> <Address>
<span> page</span> <AddressIcon address={{ hash: data.verified_twin_address_hash, is_contract: false, implementation_name: null }}/>
</Alert> <AddressLink hash={ data.verified_twin_address_hash } truncation="constant" ml={ 2 }/>
</Address>
<chakra.span mt={ 1 }>All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with </chakra.span>
<Link href={ link('address_contract_verification', { id: data.verified_twin_address_hash }) }>Verify & Publish</Link>
<span> page</span>
</Alert>
) }
</Flex> </Flex>
{ data.is_verified && ( { data.is_verified && (
<Grid templateColumns={{ base: '1fr', lg: '1fr 1fr' }} rowGap={ 4 } columnGap={ 6 } mb={ 8 }> <Grid templateColumns={{ base: '1fr', lg: '1fr 1fr' }} rowGap={ 4 } columnGap={ 6 } mb={ 8 }>
...@@ -102,10 +146,11 @@ const ContractCode = () => { ...@@ -102,10 +146,11 @@ const ContractCode = () => {
</Grid> </Grid>
) } ) }
<Flex flexDir="column" rowGap={ 6 }> <Flex flexDir="column" rowGap={ 6 }>
{ data.constructor_args && ( { constructorArgs && (
<RawDataSnippet <RawDataSnippet
data={ data.constructor_args } data={ constructorArgs }
title="Constructor Arguments" title="Constructor Arguments"
textareaMaxHeight="200px"
/> />
) } ) }
{ data.source_code && ( { data.source_code && (
...@@ -122,14 +167,14 @@ const ContractCode = () => { ...@@ -122,14 +167,14 @@ const ContractCode = () => {
<RawDataSnippet <RawDataSnippet
data={ JSON.stringify(data.compiler_settings) } data={ JSON.stringify(data.compiler_settings) }
title="Compiler Settings" title="Compiler Settings"
textareaMinHeight="200px" textareaMaxHeight="200px"
/> />
) } ) }
{ data.abi && ( { data.abi && (
<RawDataSnippet <RawDataSnippet
data={ JSON.stringify(data.abi) } data={ JSON.stringify(data.abi) }
title="Contract ABI" title="Contract ABI"
textareaMinHeight="200px" textareaMaxHeight="200px"
/> />
) } ) }
{ data.creation_bytecode && ( { data.creation_bytecode && (
...@@ -137,20 +182,27 @@ const ContractCode = () => { ...@@ -137,20 +182,27 @@ const ContractCode = () => {
data={ data.creation_bytecode } data={ data.creation_bytecode }
title="Contract creation code" title="Contract creation code"
rightSlot={ data.is_verified ? null : verificationButton } rightSlot={ data.is_verified ? null : verificationButton }
beforeSlot={ ( beforeSlot={ data.is_self_destructed ? (
<Alert status="info" whiteSpace="pre-wrap" mb={ 3 }> <Alert status="info" whiteSpace="pre-wrap" mb={ 3 }>
Contracts that self destruct in their constructors have no contract code published and cannot be verified. Contracts that self destruct in their constructors have no contract code published and cannot be verified.
Displaying the init data provided of the creating transaction. Displaying the init data provided of the creating transaction.
</Alert> </Alert>
) } ) : null }
textareaMinHeight="200px" textareaMaxHeight="200px"
/> />
) } ) }
{ data.deployed_bytecode && ( { data.deployed_bytecode && (
<RawDataSnippet <RawDataSnippet
data={ data.deployed_bytecode } data={ data.deployed_bytecode }
title="Deployed ByteCode" title="Deployed ByteCode"
textareaMinHeight="200px" textareaMaxHeight="200px"
/>
) }
{ externalLibraries && (
<RawDataSnippet
data={ externalLibraries }
title="External Libraries"
textareaMaxHeight="200px"
/> />
) } ) }
</Flex> </Flex>
......
import { Box, Flex, Text, Textarea, chakra } from '@chakra-ui/react'; import { Box, Flex, Text, chakra, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import CopyToClipboard from './CopyToClipboard'; import CopyToClipboard from './CopyToClipboard';
interface Props { interface Props {
data: string; data: React.ReactNode;
title?: string; title?: string;
className?: string; className?: string;
rightSlot?: React.ReactNode; rightSlot?: React.ReactNode;
beforeSlot?: React.ReactNode; beforeSlot?: React.ReactNode;
textareaMinHeight?: string; textareaMaxHeight?: string;
} }
const RawDataSnippet = ({ data, className, title, rightSlot, beforeSlot, textareaMinHeight }: Props) => { const RawDataSnippet = ({ data, className, title, rightSlot, beforeSlot, textareaMaxHeight }: Props) => {
// see issue in theme/components/Textarea.ts
const bgColor = useColorModeValue('#f5f5f6', '#1a1b1b');
return ( return (
<Box className={ className }> <Box className={ className }>
<Flex justifyContent={ title ? 'space-between' : 'flex-end' } alignItems="center" mb={ 3 }> <Flex justifyContent={ title ? 'space-between' : 'flex-end' } alignItems="center" mb={ 3 }>
{ title && <Text fontWeight={ 500 }>{ title }</Text> } { title && <Text fontWeight={ 500 }>{ title }</Text> }
{ rightSlot } { rightSlot }
<CopyToClipboard text={ data }/> { typeof data === 'string' && <CopyToClipboard text={ data }/> }
</Flex> </Flex>
{ beforeSlot } { beforeSlot }
<Textarea <Box
variant="filledInactive"
p={ 4 } p={ 4 }
minHeight={ textareaMinHeight || '400px' } bgColor={ bgColor }
value={ data } maxH={ textareaMaxHeight || '400px' }
fontSize="sm" fontSize="sm"
borderRadius="md" borderRadius="md"
readOnly wordBreak="break-all"
/> whiteSpace="pre-wrap"
overflowY="auto"
>
{ data }
</Box>
</Box> </Box>
); );
}; };
......
...@@ -90,6 +90,10 @@ const RoutedTabs = ({ tabs, tabListProps, rightSlot, stickyEnabled, className, . ...@@ -90,6 +90,10 @@ const RoutedTabs = ({ tabs, tabListProps, rightSlot, stickyEnabled, className, .
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ activeTabIndex, isMobile ]); }, [ activeTabIndex, isMobile ]);
if (tabs.length === 1) {
return <div>{ tabs[0].component }</div>;
}
return ( return (
<Tabs <Tabs
className={ className } className={ className }
......
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