Skip to content

Commit

Permalink
Display contract bytecode
Browse files Browse the repository at this point in the history
  • Loading branch information
csillag committed Jun 29, 2023
1 parent 33ce71f commit 28f9083
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 6 deletions.
1 change: 1 addition & 0 deletions .changelog/616.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
For contracts, display bytecode
2 changes: 1 addition & 1 deletion src/app/components/ScrollingDataDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const ScrollingDataDisplay: FC<{ data: string; fontWeight?: number }> = (
<Box
sx={{
display: 'flex',
padding: '10px 0px 0px 15px',
padding: '10px 0px 0px 0px',
flexDirection: 'column',
alignItems: 'flex-start',
gap: '10px',
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/AccountDetailsPage/AccountTokensCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const AccountTokensCard: FC<AccountTokensCardProps> = ({ type }) => {
const { t } = useTranslation()
const locationHash = useLocation().hash.replace('#', '')
const tokenLabel = t(`account.${type}` as any)
const tokenListLabel = t('tokens.title') // TODO: re-enable when we want multiple token types again t('account.tokensListTitle', { token: tokenLabel })
const tokenListLabel = t('common.tokens') // TODO: re-enable when we want multiple token types again t('account.tokensListTitle', { token: tokenLabel })
const tableColumns: TableColProps[] = [
{ key: 'name', content: t('common.name') },
{ key: 'contract', content: t('common.smartContract') },
Expand Down
76 changes: 76 additions & 0 deletions src/app/pages/AccountDetailsPage/ContractCodeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import { ScrollingDiv } from '../../components/PageLayout/ScrollingDiv'
import { useAccount } from './hook'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { useLoaderData } from 'react-router-dom'
import { CardEmptyState } from './CardEmptyState'
import Typography from '@mui/material/Typography'
import { ScrollingDataDisplay } from '../../components/ScrollingDataDisplay'
import Box from '@mui/material/Box'
import { CopyToClipboard } from '../../components/CopyToClipboard'
import { useScreenSize } from '../../hooks/useScreensize'

export const contractCodeContainerId = 'code'

const CodeDisplay: FC<{ code: string | undefined; label: string; extraTopPadding?: boolean }> = ({
code,
label,
extraTopPadding,
}) => {
const { t } = useTranslation()
const { isMobile } = useScreenSize()
return code === undefined ? null : (
<>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
my: 3,
pt: extraTopPadding ? 4 : 0,
}}
>
<Typography variant="h4" component="h4">
{label}
</Typography>
<CopyToClipboard
value={code}
label={isMobile ? t('common.copy') : t('contract.copyButton', { subject: label })}
/>
</Box>

<ScrollingDataDisplay data={code} />
</>
)
}

export const ContractCodeCard: FC = () => {
const { t } = useTranslation()
const scope = useRequiredScopeParam()
const address = useLoaderData() as string
const { isMobile } = useScreenSize()

Check warning on line 54 in src/app/pages/AccountDetailsPage/ContractCodeCard.tsx

View workflow job for this annotation

GitHub Actions / lint

'isMobile' is assigned a value but never used

const { isFetched, account } = useAccount(scope, address)
const contract = account?.evm_contract
const noCode = isFetched && !contract?.creation_bytecode && !contract?.runtime_bytecode
return (
<Card>
<ScrollingDiv id={contractCodeContainerId}>
{noCode && <CardEmptyState label={t('contract.noCode')} />}
{contract && (contract.creation_bytecode || contract.runtime_bytecode) && (
<CardContent>
<CodeDisplay code={contract.creation_bytecode} label={t('contract.creationByteCode')} />
<CodeDisplay
code={contract.runtime_bytecode}
label={t('contract.runtimeByteCode')}
extraTopPadding={!!contract.runtime_bytecode}
/>
</CardContent>
)}
</ScrollingDiv>
</Card>
)
}
6 changes: 3 additions & 3 deletions src/app/pages/AccountDetailsPage/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ export const useAccount = (scope: SearchScope, address: string) => {
}
const query = useGetRuntimeAccountsAddress(network, layer, address!)
const account = query.data?.data
const isLoading = query.isLoading
const isError = query.isError
return { account, isLoading, isError }
const { isLoading, isError, isFetched } = query

return { account, isLoading, isError, isFetched }
}

export const useAccountTransactions = (scope: SearchScope, address: string) => {
Expand Down
6 changes: 5 additions & 1 deletion src/app/pages/AccountDetailsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useAccount } from './hook'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { showEmptyAccountDetails } from '../../../config'
import { CardEmptyState } from './CardEmptyState'
import { contractCodeContainerId } from './ContractCodeCard'

export const AccountDetailsPage: FC = () => {
const { t } = useTranslation()
Expand All @@ -29,6 +30,8 @@ export const AccountDetailsPage: FC = () => {
const erc20Link = useHref(`tokens/erc-20#${accountTokenContainerId}`)
const showTxs = showEmptyAccountDetails || showErc20 || !!account?.stats.num_txns
const txLink = useHref('')
const showCode = isContract
const codeLink = useHref(`code#${contractCodeContainerId}`)

const showDetails = showTxs || showErc20

Expand All @@ -50,7 +53,8 @@ export const AccountDetailsPage: FC = () => {
<RouterTabs
tabs={[
{ label: t('common.transactions'), to: txLink, visible: showTxs },
{ label: t('tokens.title'), to: erc20Link, visible: showErc20 },
{ label: t('common.tokens'), to: erc20Link, visible: showErc20 },
{ label: t('contract.code'), to: codeLink, visible: showCode },
]}
/>
)}
Expand Down
7 changes: 7 additions & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"block": "Block",
"bytes": "{{value, number}}",
"cancel": "Cancel",
"copy": "Copy",
"createdAt": "Created at",
"data": "Data",
"emerald": "Emerald",
Expand Down Expand Up @@ -92,6 +93,12 @@
"valuePair": "{{value, number}}"
},
"contract": {
"code": "Code",
"copyButton": "Copy {{subject}}",
"creationByteCode": "Creation ByteCode",
"noCode": "There is no bytecode on record for this account. (Are you sure this is a contract?)",
"title": "Contract",
"runtimeByteCode": "Runtime ByteCode",
"title": "Contract",
"verification": {
"title": "Verification",
Expand Down
6 changes: 6 additions & 0 deletions src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { RoutingErrorPage } from './app/pages/RoutingErrorPage'
import { ThemeByNetwork, withDefaultTheme } from './app/components/ThemeByNetwork'
import { useRequiredScopeParam } from './app/hooks/useScopeParam'
import { TokensPage } from './app/pages/TokensPage'
import { ContractCodeCard } from './app/pages/AccountDetailsPage/ContractCodeCard'

const NetworkSpecificPart = () => (
<ThemeByNetwork network={useRequiredScopeParam().network}>
Expand Down Expand Up @@ -86,6 +87,11 @@ export const routes: RouteObject[] = [
element: <AccountTokensCard type="ERC20" />,
loader: addressParamLoader,
},
{
path: 'code',
element: <ContractCodeCard />,
loader: addressParamLoader,
},
],
},
{
Expand Down

0 comments on commit 28f9083

Please sign in to comment.