Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement top part of token dashboard #623

Merged
merged 15 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/623.2.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Properly display creator info for contracts.
1 change: 1 addition & 0 deletions .changelog/623.3.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
When displaying a contract that describes a token, link to the token dashboard
1 change: 1 addition & 0 deletions .changelog/623.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add token dashboard
4 changes: 2 additions & 2 deletions src/app/components/Account/AccountLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const AccountLink: FC<{
alwaysTrim?: boolean
plain?: boolean
}> = ({ scope, address, alwaysTrim, plain }) => {
const { isMobile } = useScreenSize()
const { isTablet } = useScreenSize()
const to = RouteUtils.getAccountRoute(scope, address)
return (
<Typography
Expand All @@ -26,7 +26,7 @@ export const AccountLink: FC<{
: { color: COLORS.brandDark, fontWeight: 700 }
}
>
{alwaysTrim || isMobile ? (
{alwaysTrim || isTablet ? (
<TrimLinkLabel label={address} to={to} />
) : plain ? (
address
Expand Down
51 changes: 51 additions & 0 deletions src/app/components/Account/ContractCreatorInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { FC } from 'react'
import { SearchScope } from '../../../types/searchScope'
import { Trans, useTranslation } from 'react-i18next'
import { TransactionLink } from '../Transactions/TransactionLink'
import { Layer, useGetRuntimeTransactionsTxHash } from '../../../oasis-indexer/api'
import { AppErrors } from '../../../types/errors'
import { AccountLink } from './AccountLink'
import Box from '@mui/material/Box'

const TxSender: FC<{ scope: SearchScope; txHash: string }> = ({ scope, txHash }) => {
const { t } = useTranslation()
if (scope.layer === Layer.consensus) {
csillag marked this conversation as resolved.
Show resolved Hide resolved
throw AppErrors.UnsupportedLayer
}
const query = useGetRuntimeTransactionsTxHash(scope.network, scope.layer, txHash)
const tx = query.data?.data.transactions[0]
const senderAddress = tx?.sender_0_eth || tx?.sender_0
return senderAddress ? (
<AccountLink scope={scope} address={senderAddress} alwaysTrim />
) : (
t('common.missing')
)
}

export const ContractCreatorInfo: FC<{ scope: SearchScope; address: string | undefined }> = ({
scope,
address,
}) => {
const { t } = useTranslation()
return address === undefined ? (
t('common.missing')
) : (
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 3,
}}
>
<TxSender scope={scope} txHash={address} />
&nbsp;
<Trans
t={t}
i18nKey={'contract.createdAt'}
components={{
TransactionLink: <TransactionLink scope={scope} hash={address} alwaysTrim />,
}}
/>
</Box>
)
}
55 changes: 40 additions & 15 deletions src/app/components/Account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import { CopyToClipboard } from '../../components/CopyToClipboard'
import { JazzIcon } from '../../components/JazzIcon'
import { CoinGeckoReferral } from '../../components/CoinGeckoReferral'
import { TextSkeleton } from '../../components/Skeleton'
import { type RuntimeAccount } from '../../../oasis-indexer/api'
import { EvmToken, 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/AccountTransactionsCard'
import Link from '@mui/material/Link'
import { DashboardLink } from '../../pages/DashboardPage/DashboardLink'
import { DashboardLink } from '../../pages/ParatimeDashboardPage/DashboardLink'
import { getNameForTicker, Ticker } from '../../../types/ticker'
import { TokenPriceInfo } from '../../../coin-gecko/api'
import { TransactionLink } from '../Transactions/TransactionLink'
import { ContractCreatorInfo } from './ContractCreatorInfo'
import { ContractVerificationIcon } from '../ContractVerificationIcon'
import { TokenLink } from '../Tokens/TokenLink'

export const StyledAvatarContainer = styled('dt')(({ theme }) => ({
'&&': {
Expand Down Expand Up @@ -50,17 +51,17 @@ export const FiatMoneyAmountBox = styled(Box)(() => ({

type AccountProps = {
account?: RuntimeAccount
token?: EvmToken
isLoading: boolean
tokenPriceInfo: TokenPriceInfo
showLayer?: boolean
}

export const Account: FC<AccountProps> = ({ account, isLoading, tokenPriceInfo, showLayer }) => {
export const Account: FC<AccountProps> = ({ account, token, isLoading, tokenPriceInfo, showLayer }) => {
const { t } = useTranslation()
const { isMobile } = useScreenSize()
const balance = account?.balances[0]?.balance ?? '0'
const balance = account?.balances[0]?.balance
const address = account ? account.address_eth ?? account.address : undefined
const creationTxHash = account?.evm_contract?.eth_creation_tx ?? account?.evm_contract?.creation_tx

const transactionsLabel = account ? account.stats.num_txns.toLocaleString() : ''
const transactionsAnchor = account
Expand All @@ -70,14 +71,15 @@ export const Account: FC<AccountProps> = ({ account, isLoading, tokenPriceInfo,
)}#${accountTransactionsContainerId}`
: undefined

const token = account?.ticker || Ticker.ROSE
const tickerName = getNameForTicker(t, token)
const nativeToken = account?.ticker || Ticker.ROSE
const nativeTickerName = getNameForTicker(t, nativeToken)
const {
isLoading: isPriceLoading,
price: tokenFiatValue,
isFree: isTokenFree,
hasUsedCoinGecko,
} = tokenPriceInfo
const contract = account?.evm_contract

return (
<>
Expand All @@ -100,7 +102,20 @@ export const Account: FC<AccountProps> = ({ account, isLoading, tokenPriceInfo,
<CopyToClipboard value={address!} />
</dd>

{account?.evm_contract && (
{token && (
<>
<dt>{t('common.token')}</dt>
<dd>
<TokenLink
scope={account}
address={token.eth_contract_addr || token.contract_addr}
name={token.name}
/>
</dd>
</>
)}

{contract && (
<>
<dt>{t('contract.verification.title')}</dt>
<dd>
Expand All @@ -111,17 +126,25 @@ export const Account: FC<AccountProps> = ({ account, isLoading, tokenPriceInfo,
</dd>
</>
)}
{creationTxHash && (

{contract && (
<>
<dt>{t('common.createdAt')}</dt>
<dt>{t('contract.creator')}</dt>
<dd>
<TransactionLink scope={account} hash={creationTxHash} />
<ContractCreatorInfo
scope={account}
address={contract.eth_creation_tx || contract.creation_tx}
/>
</dd>
</>
)}

<dt>{t('common.balance')}</dt>
<dd>{t('common.valueInToken', { value: balance, ticker: tickerName })}</dd>
<dd>
{balance === undefined
? t('common.missing')
: t('common.valueInToken', { value: balance, ticker: nativeTickerName })}
</dd>

<dt>{t('common.tokens')}</dt>
<dd>
Expand Down Expand Up @@ -159,10 +182,12 @@ export const Account: FC<AccountProps> = ({ account, isLoading, tokenPriceInfo,
</dd>

<dt>{t('account.totalReceived')}</dt>
<dd>{t('common.valueInToken', { value: account.stats.total_received, ticker: tickerName })}</dd>
<dd>
{t('common.valueInToken', { value: account.stats.total_received, ticker: nativeTickerName })}
</dd>

<dt>{t('account.totalSent')}</dt>
<dd>{t('common.valueInToken', { value: account.stats.total_sent, ticker: tickerName })}</dd>
<dd>{t('common.valueInToken', { value: account.stats.total_sent, ticker: nativeTickerName })}</dd>
</StyledDescriptionList>
)}
</>
Expand Down
10 changes: 7 additions & 3 deletions src/app/components/ContractVerificationIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const StyledBox = styled(Box, {
return {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '28px',
fontSize: '12px',
backgroundColor: statusBgColor[status],
Expand All @@ -47,9 +46,14 @@ const StyledBox = styled(Box, {
type ContractVerificationIconProps = {
verified: boolean
address_eth: string
noLink?: boolean
}

export const ContractVerificationIcon: FC<ContractVerificationIconProps> = ({ verified, address_eth }) => {
export const ContractVerificationIcon: FC<ContractVerificationIconProps> = ({
verified,
address_eth,
noLink = false,
}) => {
const { t } = useTranslation()
const status: VerificationStatus = verified ? 'verified' : 'unverified'
const statusLabel: Record<VerificationStatus, string> = {
Expand All @@ -65,7 +69,7 @@ export const ContractVerificationIcon: FC<ContractVerificationIconProps> = ({ ve
{statusIcon[status]}
</StyledBox>
&nbsp; &nbsp;
{verified && (
{verified && !noLink && (
<Typography component="span" sx={{ fontSize: '12px', color: COLORS.brandExtraDark }}>
<Trans
t={t}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FC, memo } from 'react'
import { Select, SelectOptionBase } from '../../../components/Select'
import { Select, SelectOptionBase } from '../../Select'
import { ChartDuration } from '../../../utils/chart-utils'
import { useTranslation } from 'react-i18next'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type SnapshotCardProps = PropsWithChildren & {
label?: string
title: ReactNode
withContentPadding?: boolean
withConstantHeight?: boolean
}

export const SnapshotCard: FC<SnapshotCardProps> = ({
Expand All @@ -39,12 +40,13 @@ export const SnapshotCard: FC<SnapshotCardProps> = ({
title,
label,
withContentPadding = true,
withConstantHeight = false,
}) => {
return (
<StyledCard>
<CardHeader component="h5" title={title} sx={{ pb: 0, pl: 4, pt: 4 }} />
<StyledCardContent withContentPadding={withContentPadding}>{children}</StyledCardContent>
{(badge || label) && (
{(badge || label || withConstantHeight) && (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This solves this issue:
image

<CardActions sx={{ minHeight: 60 }}>
<Box
sx={{
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Tokens/TokenDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
import { TokenLink } from './TokenLink'
import { CopyToClipboard } from '../CopyToClipboard'
import { AccountLink } from '../Account/AccountLink'
import { DashboardLink } from '../../pages/DashboardPage/DashboardLink'
import { DashboardLink } from '../../pages/ParatimeDashboardPage/DashboardLink'
import { LongDataDisplay } from '../LongDataDisplay'

export const TokenDetails: FC<{
Expand Down Expand Up @@ -48,7 +48,7 @@ export const TokenDetails: FC<{
<dt>{t(isMobile ? 'tokens.holdersCount_short' : 'tokens.holdersCount')}</dt>
<dd>{token.num_holders.toLocaleString()}</dd>

<dt>{t('tokens.supply')}</dt>
<dt>{t('tokens.totalSupply')}</dt>
<dd>
<LongDataDisplay data={token.total_supply || t('common.missing')} threshold={100} fontWeight={400} />
</dd>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/Tokens/TokenList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const TokenList = (props: TokensProps) => {
content: t('tokens.holdersCount'),
align: TableCellAlign.Right,
},
{ key: 'supply', content: t('tokens.supply'), align: TableCellAlign.Right },
{ key: 'supply', content: t('tokens.totalSupply'), align: TableCellAlign.Right },
{ key: 'ticker', content: t('common.ticker'), align: TableCellAlign.Right },
]

Expand Down
16 changes: 13 additions & 3 deletions src/app/pages/AccountDetailsPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@ import { RouterTabs } from '../../components/RouterTabs'
import { TokenPriceInfo, useTokenPrice } from '../../../coin-gecko/api'
import { Ticker } from '../../../types/ticker'

import { EvmTokenType, RuntimeAccount } from '../../../oasis-indexer/api'
import { EvmToken, EvmTokenType, RuntimeAccount } from '../../../oasis-indexer/api'
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'
import { useTokenInfo } from '../TokenDashboardPage/hook'

export const AccountDetailsPage: FC = () => {
const { t } = useTranslation()

const scope = useRequiredScopeParam()
const address = useLoaderData() as string
const { account, isLoading, isError } = useAccount(scope, address)
const { token } = useTokenInfo(scope, address)

const tokenPriceInfo = useTokenPrice(account?.ticker || Ticker.ROSE)
const isContract = !!account?.evm_contract
Expand All @@ -46,6 +48,7 @@ export const AccountDetailsPage: FC = () => {
isLoading={isLoading}
isError={isError}
account={account}
token={token}
tokenPriceInfo={tokenPriceInfo}
/>
</SubPageCard>
Expand All @@ -66,13 +69,20 @@ export const AccountDetailsView: FC<{
isLoading: boolean
isError: boolean
account: RuntimeAccount | undefined
token?: EvmToken
tokenPriceInfo: TokenPriceInfo
showLayer?: boolean
}> = ({ isLoading, isError, account, tokenPriceInfo, showLayer }) => {
}> = ({ isLoading, isError, account, token, tokenPriceInfo, showLayer }) => {
const { t } = useTranslation()
return isError ? (
<CardEmptyState label={t('account.cantLoadDetails')} />
) : (
<Account account={account} isLoading={isLoading} tokenPriceInfo={tokenPriceInfo} showLayer={showLayer} />
<Account
account={account}
token={token}
isLoading={isLoading}
tokenPriceInfo={tokenPriceInfo}
showLayer={showLayer}
/>
)
}
2 changes: 1 addition & 1 deletion src/app/pages/BlockDetailPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { transactionsContainerId } from './TransactionsCard'
import { BlockLink, BlockHashLink } from '../../components/Blocks/BlockLink'
import { RouteUtils } from '../../utils/route-utils'
import { useRequiredScopeParam } from '../../hooks/useScopeParam'
import { DashboardLink } from '../DashboardPage/DashboardLink'
import { DashboardLink } from '../ParatimeDashboardPage/DashboardLink'

export const BlockDetailPage: FC = () => {
const { t } = useTranslation()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import startOfMonth from 'date-fns/startOfMonth'
import { SnapshotCard } from './SnapshotCard'
import { SnapshotCard } from '../../components/Snapshots/SnapshotCard'
import { BarChart } from '../../components/charts/BarChart'
import {
useGetLayerStatsActiveAccounts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import OfflineBoltIcon from '@mui/icons-material/OfflineBolt'
import InfoIcon from '@mui/icons-material/Info'
import { SnapshotCard } from './SnapshotCard'
import { SnapshotCard } from '../../components/Snapshots/SnapshotCard'
import { COLORS } from '../../../styles/theme/colors'
import { Layer, useGetRuntimeStatus } from '../../../oasis-indexer/api'
import { AppErrors } from '../../../types/errors'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Typography from '@mui/material/Typography'
import { useScreenSize } from '../../hooks/useScreensize'
import { useTheme } from '@mui/material/styles'
import { styled } from '@mui/material/styles'
import { DurationSelect } from './DurationSelect'
import { DurationSelect } from '../../components/Snapshots/DurationSelect'
import { TransactionsChartCard } from './TransactionsChartCard'
import { RosePriceCard } from './RosePriceCard'
import { Nodes } from './Nodes'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import Box from '@mui/material/Box'
import { styled } from '@mui/material/styles'
import { CoinGeckoReferral } from '../../components/CoinGeckoReferral'
import { SnapshotCard } from './SnapshotCard'
import { SnapshotCard } from '../../components/Snapshots/SnapshotCard'
import { useGetRosePrice } from '../../../coin-gecko/api'
import { COLORS } from '../../../styles/theme/colors'
import Typography from '@mui/material/Typography'
Expand Down
Loading