Skip to content

Commit

Permalink
Merge pull request #616 from oasisprotocol/csillag/more-account-details
Browse files Browse the repository at this point in the history
Display Contract ByteCode
  • Loading branch information
csillag committed Jun 29, 2023
2 parents 0438ec0 + 9e2a217 commit 7b6a060
Show file tree
Hide file tree
Showing 22 changed files with 188 additions and 44 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/Account/ShowMoreTokensLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { styled } from '@mui/material/styles'
import { COLORS } from '../../../styles/theme/colors'
import { EvmTokenType, RuntimeAccount, type Token } from '../../../oasis-indexer/api'
import { RouteUtils } from '../../utils/route-utils'
import { accountTokenContainerId } from '../../pages/AccountDetailsPage/TokensCard'
import { accountTokenContainerId } from '../../pages/AccountDetailsPage/AccountTokensCard'

export const StyledLink = styled(RouterLink)(({ theme }) => ({
color: COLORS.brandDark,
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { type RuntimeAccount } from '../../../oasis-indexer/api'
import { TokenPills } from './TokenPills'
import { AccountLink } from './AccountLink'
import { RouteUtils } from '../../utils/route-utils'
import { accountTransactionsContainerId } from '../../pages/AccountDetailsPage/TransactionsCard'
import { accountTransactionsContainerId } from '../../pages/AccountDetailsPage/AccountTransactionsCard'
import Link from '@mui/material/Link'
import { DashboardLink } from '../../pages/DashboardPage/DashboardLink'
import { getNameForTicker, Ticker } from '../../../types/ticker'
Expand Down
24 changes: 19 additions & 5 deletions src/app/components/CopyToClipboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy'
import { COLORS } from '../../../styles/theme/colors'
import ButtonBase from '@mui/material/ButtonBase'
import { styled } from '@mui/material/styles'
import Button from '@mui/material/Button'

const clipboardTooltipDuration = 2000

type CopyToClipboardProps = {
value: string
label?: string
}

const StyledButton = styled(ButtonBase)(({ theme }) => ({
const StyledIconButton = styled(ButtonBase)(({ theme }) => ({
display: 'inline-flex',
alignItems: 'center',
border: 0,
Expand All @@ -24,7 +26,7 @@ const StyledButton = styled(ButtonBase)(({ theme }) => ({
marginLeft: theme.spacing(4),
}))

export const CopyToClipboard: FC<CopyToClipboardProps> = ({ value }) => {
export const CopyToClipboard: FC<CopyToClipboardProps> = ({ value, label }) => {
const { t } = useTranslation()
const timeout = useRef<number | undefined>(undefined)
const ariaLabel = t('clipboard.label')
Expand All @@ -51,9 +53,21 @@ export const CopyToClipboard: FC<CopyToClipboardProps> = ({ value }) => {

return (
<Tooltip arrow onOpen={hideTooltip} open={isCopied} placement="right" title={t('clipboard.success')}>
<StyledButton color="inherit" onClick={handleCopyToClipboard} aria-label={ariaLabel}>
<ContentCopyIcon sx={{ fontSize: '1.25em', color: COLORS.brandDark }} />
</StyledButton>
{label ? (
<Button
variant="outlined"
color="secondary"
sx={{ textTransform: 'capitalize' }}
onClick={handleCopyToClipboard}
aria-label={ariaLabel}
>
{label}
</Button>
) : (
<StyledIconButton color="inherit" onClick={handleCopyToClipboard} aria-label={ariaLabel}>
<ContentCopyIcon sx={{ fontSize: '1.25em', color: COLORS.brandDark }} />
</StyledIconButton>
)}
</Tooltip>
)
}
7 changes: 1 addition & 6 deletions src/app/components/LongDataDisplay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@ export const LongDataDisplay: FC<{ data: string; threshold: number; fontWeight?:
}
return (
<div>
<Collapse
orientation={'vertical'}
in={showData}
onClick={() => setShowData(true)}
collapsedSize={'3em'}
>
<Collapse orientation="vertical" in={showData} onClick={() => setShowData(true)} collapsedSize="3em">
<Typography
variant="mono"
sx={{
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/ParaTimePicker/LayerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const DisabledLayerMenuItem: FC<BaseLayerMenuItemProps> = ({ divider, lay
const labels = getLayerLabels(t)

return (
<Tooltip arrow placement="top" title={'Coming soon'}>
<Tooltip arrow placement="top" title="Coming soon">
{/* Div is needed because we need an element with enabled pointer-events to make Tooltip work */}
<div>
<MenuItem disabled divider={divider}>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/RoundedBalance/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('RoundedBalance', () => {

describe('RoundedRoseBalance', () => {
it('should render value with ROSE ticker symbol', () => {
render(<RoundedBalance value="0.002231" ticker={'ROSE'} />)
render(<RoundedBalance value="0.002231" ticker="ROSE" />)

expect(screen.getByText('0.00223… ROSE')).toBeInTheDocument()
})
Expand Down
44 changes: 44 additions & 0 deletions src/app/components/ScrollingDataDisplay/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { FC } from 'react'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import { COLORS } from '../../../styles/theme/colors'

export const ScrollingDataDisplay: FC<{ data: string; fontWeight?: number }> = ({
data,
fontWeight = 700,
}) => {
return (
<Box
sx={{
display: 'flex',
padding: '10px 0px 0px 0px',
flexDirection: 'column',
alignItems: 'flex-start',
gap: '10px',
}}
>
<Box
sx={{
borderRadius: '5px',
background: COLORS.grayLight,
border: `1px solid ${COLORS.grayMedium}`,
height: '349px',
overflowY: 'scroll',
p: 3,
}}
>
<Typography
variant="mono"
fontSize={16}
sx={{
fontWeight,
overflowWrap: 'anywhere',
}}
color={COLORS.grayMedium}
>
{data}
</Typography>
</Box>
</Box>
)
}
2 changes: 1 addition & 1 deletion src/app/components/Select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const TertiaryButton = forwardRef(
const { t } = useTranslation()

return (
<StyledButton {...restProps} ref={ref} color={'tertiary'}>
<StyledButton {...restProps} ref={ref} color="tertiary">
<Typography variant="select">{children ? children : t('select.placeholder')}</Typography>
{ownerState.open ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</StyledButton>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/TransactionStatusIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const statusFgColor: Record<TxStatus, string> = {
}

const statusIcon: Record<TxStatus, ReactNode> = {
unknown: <HelpIcon color={'inherit'} fontSize="inherit" />,
unknown: <HelpIcon color="inherit" fontSize="inherit" />,
success: <CheckCircleIcon color="success" fontSize="inherit" />,
failure: <CancelIcon color="error" fontSize="inherit" />,
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Transactions/LogEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export const TransactionLogEvent: FC<{

return (
<>
{!isFirst && <Divider variant={'card'} />}
{!isFirst && <Divider variant="card" />}
<StyledDescriptionList titleWidth={isMobile ? '100px' : '200px'}>
{decoded && (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ import { ScrollingDiv } from '../../components/PageLayout/ScrollingDiv'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { useAccount } from './hook'

type TokensCardProps = {
type AccountTokensCardProps = {
type: EvmTokenType
}

export const accountTokenContainerId = 'tokens'

export const TokensCard: FC<TokensCardProps> = ({ type }) => {
export const AccountTokensCard: FC<AccountTokensCardProps> = ({ type }) => {
const scope = useRequiredScopeParam()
const address = useLoaderData() as string
const { t } = useTranslation()
const locationHash = useLocation().hash.replace('#', '')
const tokenLabel = t(`account.${type}` as any)
const tokenListLabel = 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,19 @@ import { NUMBER_OF_ITEMS_ON_SEPARATE_PAGE } from '../../config'
import { ErrorBoundary } from '../../components/ErrorBoundary'
import { ScrollingDiv } from '../../components/PageLayout/ScrollingDiv'
import { CardEmptyState } from './CardEmptyState'
import { useTransactions } from './hook'
import { useAccountTransactions } from './hook'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { useLoaderData } from 'react-router-dom'

export const accountTransactionsContainerId = 'transactions'

export const TransactionsCard: FC = () => {
export const AccountTransactionsCard: FC = () => {
const { t } = useTranslation()
const scope = useRequiredScopeParam()
const address = useLoaderData() as string

const { isLoading, isFetched, transactions, pagination, totalCount, isTotalCountClipped } = useTransactions(
scope,
address,
)
const { isLoading, isFetched, transactions, pagination, totalCount, isTotalCountClipped } =
useAccountTransactions(scope, address)
return (
<Card>
<ScrollingDiv id={accountTransactionsContainerId}>
Expand Down
75 changes: 75 additions & 0 deletions src/app/pages/AccountDetailsPage/ContractCodeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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 { 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.creation_bytecode}
/>
</CardContent>
)}
</ScrollingDiv>
</Card>
)
}
8 changes: 4 additions & 4 deletions src/app/pages/AccountDetailsPage/hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ 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 useTransactions = (scope: SearchScope, address: string) => {
export const useAccountTransactions = (scope: SearchScope, address: string) => {
const { network, layer } = scope
const pagination = useSearchParamsPagination('page')
const offset = (pagination.selectedPage - 1) * NUMBER_OF_ITEMS_ON_SEPARATE_PAGE
Expand Down
8 changes: 6 additions & 2 deletions src/app/pages/AccountDetailsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import { TokenPriceInfo, useTokenPrice } from '../../../coin-gecko/api'
import { Ticker } from '../../../types/ticker'

import { EvmTokenType, RuntimeAccount } from '../../../oasis-indexer/api'
import { accountTokenContainerId } from './TokensCard'
import { accountTokenContainerId } from './AccountTokensCard'
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('account.ERC20'), to: erc20Link, visible: showErc20 },
{ label: t('common.tokens'), to: erc20Link, visible: showErc20 },
{ label: t('contract.code'), to: codeLink, visible: showCode },
]}
/>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/SearchResultsPage/NoResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const NoResults: FC<{
i18nKey="search.noResults.description"
components={{
OptionalBreak: <OptionalBreak />,
HomeLink: <Link component={RouterLink} to={'/'} />,
HomeLink: <Link component={RouterLink} to="/" />,
}}
/>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('SearchResultsView', () => {
hasUsedCoinGecko: false,
},
}}
title={'test search'}
title="test search"
networkForTheme={Network.mainnet}
/>,
)
Expand All @@ -59,7 +59,7 @@ describe('SearchResultsView', () => {
renderWithProviders(
<SearchResultsList
searchResults={[suggestedParsedAccountResult]}
title={'test search'}
title="test search"
networkForTheme={Network.mainnet}
tokenPrices={{
[Network.mainnet]: {
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/SearchResultsPage/notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const HideMoreResults: FC<{ theme: Theme; onHide: () => void }> = ({ them
<NotificationBox theme={theme} onClick={onHide}>
<ZoomOut />
<span>
<Trans i18nKey={'search.otherResults.clickToHide'} />
<Trans i18nKey="search.otherResults.clickToHide" />
</span>
</NotificationBox>
)
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/TransactionDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const TransactionDetailPage: FC = () => {
return (
<PageLayout>
{warningMultipleTransactionsSameHash && (
<StyledAlert severity={'error'}>{t('transaction.warningMultipleTransactionsSameHash')}</StyledAlert>
<StyledAlert severity="error">{t('transaction.warningMultipleTransactionsSameHash')}</StyledAlert>
)}
<SubPageCard
featured
Expand Down

0 comments on commit 7b6a060

Please sign in to comment.