Commit 1cec1447 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #264 from blockscout/tx-api-update

tx api update
parents 37c11d04 43f1e0dd
export interface AddressTag {
label: string;
display_name: string;
address_hash: string;
}
export interface WatchlistName {
label: string;
display_name: string;
}
export interface AddressParam {
hash: string;
implementation_name: string;
name: string;
name: string | null;
is_contract: boolean;
private_tags: Array<AddressTag> | null;
watchlist_names: Array<WatchlistName> | null;
public_tags: Array<AddressTag> | null;
}
......@@ -10,10 +10,11 @@ export interface InternalTransaction {
from: AddressParam;
to: AddressParam;
created_contract: AddressParam;
value: number;
value: string;
index: number;
block: number;
timestamp: string;
gas_limit: string;
}
export interface InternalTransactionsResponse {
......
export interface Reward {
reward: number;
reward: string;
type: 'Miner Reward' | 'Validator Reward' | 'Emission Reward' | 'Chore Reward' | 'Uncle Reward';
}
export type TokenType = 'ERC-20' | 'ERC-721' | 'ERC-1155';
export interface TokenInfo {
address: string;
type: TokenType;
symbol: string | null;
name: string | null;
decimals: string | null;
holders: string | null;
exchange_rate: string | null;
}
export type TokenInfoGeneric<Type extends TokenType> = Omit<TokenInfo, 'type'> & { type: Type };
import type { AddressParam } from './addressParams';
import type { TokenInfoGeneric } from './tokenInfo';
export type ERC1155TotalPayload = {
export type Erc20TotalPayload = {
decimals: string | null;
value: string;
}
export type Erc721TotalPayload = {
token_id: string;
}
export type Erc1155TotalPayload = {
decimals: string | null;
value: string;
token_id: string;
}
export type TokenTransfer = (
{
token_type: 'ERC-20';
total: {
value: string;
};
token: TokenInfoGeneric<'ERC-20'>;
total: Erc20TotalPayload;
} |
{
token_type: 'ERC-721';
total: {
token_id: string;
};
token: TokenInfoGeneric<'ERC-721'>;
total: Erc721TotalPayload;
} |
{
token_type: 'ERC-1155';
total: ERC1155TotalPayload | Array<ERC1155TotalPayload>;
token: TokenInfoGeneric<'ERC-1155'>;
total: Erc1155TotalPayload | Array<Erc1155TotalPayload>;
}
) & TokenTransferBase
interface TokenTransferBase {
type: 'token_transfer' | 'token_burning' | 'token_spawning' | 'token_minting';
txHash: string;
tx_hash: string;
from: AddressParam;
to: AddressParam;
token_address: string;
token_symbol: string;
exchange_rate: string;
}
......@@ -38,6 +38,7 @@ export interface Transaction {
token_transfers: Array<TokenTransfer> | null;
token_transfers_overflow: boolean;
exchange_rate: string;
tx_tag: string | null;
}
export interface TransactionsResponse {
......
......@@ -158,6 +158,19 @@ const BlockDetails = () => {
) }
</DetailsInfoItem>
) }
{ data.rewards
?.filter(({ type }) => type !== 'Validator Reward' && type !== 'Miner Reward')
.map(({ type, reward }) => (
<DetailsInfoItem
key={ type }
title={ type }
// is this text correct for validators?
hint={ `Amount of distributed reward. ${ capitalize(validatorTitle) }s receive a static block reward + Tx fees + uncle fees.` }
>
{ BigNumber(reward).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</DetailsInfoItem>
))
}
{ sectionGap }
......@@ -298,18 +311,6 @@ const BlockDetails = () => {
>
{ data.nonce }
</DetailsInfoItem>
{ data.rewards
?.filter(({ type }) => type !== 'Validator Reward' && type !== 'Miner Reward')
.map(({ type, reward }) => (
<DetailsInfoItem
key={ type }
title={ type }
// is this text correct for validators?
hint={ `Amount of distributed reward. ${ capitalize(validatorTitle) }s receive a static block reward + Tx fees + uncle fees.` }
>
{ BigNumber(reward).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</DetailsInfoItem>
)) }
</>
) }
</Grid>
......
import { Flex, Link, Spinner, Text, Box, Icon, useColorModeValue } from '@chakra-ui/react';
import { Flex, Link, Spinner, Text, Box, Icon } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import capitalize from 'lodash/capitalize';
import React from 'react';
......@@ -7,8 +7,7 @@ import type { Block } from 'types/api/block';
import appConfig from 'configs/app/config';
import flameIcon from 'icons/flame.svg';
import getBlockReward from 'lib/block/getBlockReward';
import { WEI } from 'lib/consts';
import { WEI, ZERO } from 'lib/consts';
import link from 'lib/link/link';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import BlockTimestamp from 'ui/blocks/BlockTimestamp';
......@@ -24,14 +23,17 @@ interface Props {
}
const BlocksListItem = ({ data, isPending, enableTimeIncrement }: Props) => {
const spinnerEmptyColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
const { totalReward, burntFees, txFees } = getBlockReward(data);
const totalReward = data.rewards
?.map(({ reward }) => BigNumber(reward))
.reduce((result, item) => result.plus(item), ZERO) || ZERO;
const burntFees = BigNumber(data.burnt_fees || 0);
const txFees = BigNumber(data.tx_fees || 0);
return (
<AccountListItemMobile rowGap={ 3 }>
<Flex justifyContent="space-between" w="100%">
<Flex columnGap={ 2 } alignItems="center">
{ isPending && <Spinner size="sm" color="blue.500" emptyColor={ spinnerEmptyColor }/> }
{ isPending && <Spinner size="sm"/> }
<Link
fontWeight={ 600 }
href={ link('block', { id: String(data.height) }) }
......
......@@ -5,8 +5,7 @@ import React from 'react';
import type { Block } from 'types/api/block';
import flameIcon from 'icons/flame.svg';
import getBlockReward from 'lib/block/getBlockReward';
import { WEI } from 'lib/consts';
import { WEI, ZERO } from 'lib/consts';
import link from 'lib/link/link';
import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import AddressLink from 'ui/shared/address/AddressLink';
......@@ -20,7 +19,11 @@ interface Props {
}
const BlocksTableItem = ({ data, isPending, enableTimeIncrement }: Props) => {
const { totalReward, burntFees, txFees } = getBlockReward(data);
const totalReward = data.rewards
?.map(({ reward }) => BigNumber(reward))
.reduce((result, item) => result.plus(item), ZERO) || ZERO;
const burntFees = BigNumber(data.burnt_fees || 0);
const txFees = BigNumber(data.tx_fees || 0);
return (
<Tr>
......
import { Flex, Link, Icon } from '@chakra-ui/react';
import { Flex, Link, Icon, Tag } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import eastArrowIcon from 'icons/arrows/east.svg';
import link from 'lib/link/link';
import useFetch from 'lib/hooks/useFetch';
import isBrowser from 'lib/isBrowser';
import networkExplorers from 'lib/networks/networkExplorers';
import ExternalLink from 'ui/shared/ExternalLink';
import Page from 'ui/shared/Page/Page';
......@@ -28,6 +31,15 @@ const TABS: Array<RoutedTab> = [
const TransactionPageContent = () => {
const router = useRouter();
const fetch = useFetch();
const { data } = useQuery<unknown, unknown, Transaction>(
[ 'tx', router.query.id ],
async() => await fetch(`/api/transactions/${ router.query.id }`),
{
enabled: Boolean(router.query.id),
},
);
const explorersLinks = networkExplorers
.filter((explorer) => explorer.paths.tx)
......@@ -36,15 +48,19 @@ const TransactionPageContent = () => {
return <ExternalLink key={ explorer.baseUrl } title={ `Open in ${ explorer.title }` } href={ url.toString() }/>;
});
const hasGoBackLink = isBrowser() && window.document.referrer.includes('/txs');
return (
<Page>
{ /* TODO should be shown only when navigating from txs list */ }
<Link mb={ 6 } display="inline-flex" href={ link('txs') }>
<Icon as={ eastArrowIcon } boxSize={ 6 } mr={ 2 } transform="rotate(180deg)"/>
Transactions
</Link>
{ hasGoBackLink && (
<Link mb={ 6 } display="inline-flex" href={ window.document.referrer }>
<Icon as={ eastArrowIcon } boxSize={ 6 } mr={ 2 } transform="rotate(180deg)"/>
Transactions
</Link>
) }
<Flex alignItems="flex-start" flexDir={{ base: 'column', lg: 'row' }}>
<PageTitle text="Transaction details"/>
{ data?.tx_tag && <Tag my={ 2 } ml={ 3 }>{ data.tx_tag }</Tag> }
{ explorersLinks.length > 0 && (
<Flex
alignItems="center"
......
......@@ -2,22 +2,18 @@ import { Box, Text, chakra } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { Unit } from 'types/unit';
import getValueWithUnit from 'lib/getValueWithUnit';
interface Props {
value: string;
unit?: Unit;
currency?: string;
exchangeRate?: string | null;
className?: string;
accuracy?: number;
accuracyUsd?: number;
decimals?: string | null;
}
const CurrencyValue = ({ value, currency = '', unit, exchangeRate, className, accuracy, accuracyUsd }: Props) => {
const valueCurr = getValueWithUnit(value, unit);
const CurrencyValue = ({ value, currency = '', decimals, exchangeRate, className, accuracy, accuracyUsd }: Props) => {
const valueCurr = BigNumber(value).div(BigNumber(10 ** Number(decimals || '18')));
const valueResult = accuracy ? valueCurr.dp(accuracy).toFormat() : valueCurr.toFormat();
let usdContent;
......
......@@ -7,7 +7,7 @@ const EmptyElement = () => null;
interface Props {
hash: string;
name?: string;
name?: string | null;
className?: string;
}
......
......@@ -5,9 +5,9 @@ import link from 'lib/link/link';
import TokenLogo from 'ui/shared/TokenLogo';
interface Props {
symbol: string;
symbol?: string | null;
hash: string;
name: string;
name?: string | null;
className?: string;
}
......@@ -20,7 +20,7 @@ const TokenSnippet = ({ symbol, hash, name, className }: Props) => {
<Link href={ url } target="_blank">
{ name }
</Link>
<Text variant="secondary">({ symbol })</Text>
{ symbol && <Text variant="secondary">({ symbol })</Text> }
</Center>
);
};
......
import { Link, chakra, shouldForwardProp, Tooltip, Box } from '@chakra-ui/react';
import type { HTMLAttributeAnchorTarget } from 'react';
import React from 'react';
import link from 'lib/link/link';
......@@ -7,15 +8,16 @@ import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
interface Props {
type?: 'address' | 'transaction' | 'token' | 'block';
alias?: string;
alias?: string | null;
className?: string;
hash: string;
truncation?: 'constant' | 'dynamic'| 'none';
fontWeight?: string;
id?: string;
target?: HTMLAttributeAnchorTarget;
}
const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id, fontWeight }: Props) => {
const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id, fontWeight, target }: Props) => {
let url;
if (type === 'transaction') {
url = link('tx', { id: id || hash });
......@@ -49,7 +51,7 @@ const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id,
<Link
className={ className }
href={ url }
target="_blank"
target={ target || '_blank' }
overflow="hidden"
whiteSpace="nowrap"
>
......
......@@ -3,27 +3,33 @@ import React from 'react';
import nftIcon from 'icons/nft_shield.svg';
import link from 'lib/link/link';
import AddressLink from 'ui/shared/address/AddressLink';
import TokenSnippet from 'ui/shared/TokenSnippet';
interface Props {
value: string;
tokenId: string;
hash: string;
symbol: string;
name?: string | null;
symbol?: string | null;
}
const NftTokenTransferSnippet = (props: Props) => {
const num = props.value === '1' ? '' : props.value;
const url = link('token_instance_item', { hash: props.hash, id: props.tokenId });
const NftTokenTransferSnippet = ({ value, name, hash, symbol, tokenId }: Props) => {
const num = value === '1' ? '' : value;
const url = link('token_instance_item', { hash: hash, id: tokenId });
return (
<Flex alignItems="center" columnGap={ 3 } rowGap={ 2 } flexWrap="wrap">
<Text fontWeight={ 500 } as="span">For { num } token ID:</Text>
<Box display="inline-flex" alignItems="center">
<Icon as={ nftIcon } boxSize={ 6 } mr={ 1 }/>
<Link href={ url } fontWeight={ 600 }>{ props.tokenId }</Link>
<Link href={ url } fontWeight={ 600 }>{ tokenId }</Link>
</Box>
<TokenSnippet symbol={ props.symbol } hash={ props.hash } name="Foo"/>
{ name ? (
<TokenSnippet symbol={ symbol } hash={ hash } name={ name }/>
) : (
<AddressLink hash={ hash } truncation="constant" type="token"/>
) }
</Flex>
);
};
......
import { Flex, Icon, Text } from '@chakra-ui/react';
import React from 'react';
import type { TokenTransfer as TTokenTransfer } from 'types/api/tokenTransfer';
import type { TokenTransfer as TTokenTransfer, Erc20TotalPayload, Erc721TotalPayload, Erc1155TotalPayload } from 'types/api/tokenTransfer';
import rightArrowIcon from 'icons/arrows/east.svg';
import { space } from 'lib/html-entities';
......@@ -12,43 +12,47 @@ import NftTokenTransferSnippet from 'ui/tx/NftTokenTransferSnippet';
type Props = TTokenTransfer;
const TokenTransfer = (props: Props) => {
const TokenTransfer = ({ token, total, to, from }: Props) => {
const isColumnLayout = props.token_type === 'ERC-1155' && Array.isArray(props.total);
const tokenSnippet = <TokenSnippet symbol={ props.token_symbol } hash={ props.token_address } name="Foo" ml={ 3 }/>;
const isColumnLayout = token.type === 'ERC-1155' && Array.isArray(total);
const tokenSnippet = <TokenSnippet symbol={ token.symbol } hash={ token.address } name={ token.name } ml={ 3 }/>;
const content = (() => {
switch (props.token_type) {
case 'ERC-20':
switch (token.type) {
case 'ERC-20': {
const payload = total as Erc20TotalPayload;
return (
<Flex>
<Text fontWeight={ 500 } as="span">For:{ space }
<CurrencyValue value={ props.total.value } unit="ether" exchangeRate={ props.exchange_rate } fontWeight={ 600 }/>
<CurrencyValue value={ payload.value } exchangeRate={ token.exchange_rate } fontWeight={ 600 }/>
</Text>
{ tokenSnippet }
</Flex>
);
}
case 'ERC-721': {
const payload = total as Erc721TotalPayload;
return (
<NftTokenTransferSnippet
tokenId={ props.total.token_id }
tokenId={ payload.token_id }
value="1"
hash={ props.token_address }
symbol={ props.token_symbol }
hash={ token.address }
symbol={ token.symbol }
/>
);
}
case 'ERC-1155': {
const items = Array.isArray(props.total) ? props.total : [ props.total ];
const payload = total as Erc1155TotalPayload | Array<Erc1155TotalPayload>;
const items = Array.isArray(payload) ? payload : [ payload ];
return items.map((item) => (
<NftTokenTransferSnippet
key={ item.token_id }
tokenId={ item.token_id }
value={ item.value }
hash={ props.token_address }
symbol={ props.token_symbol }
hash={ token.address }
symbol={ token.symbol }
/>
));
}
......@@ -64,9 +68,9 @@ const TokenTransfer = (props: Props) => {
flexDir={ isColumnLayout ? 'column' : 'row' }
>
<Flex alignItems="center">
<AddressLink fontWeight="500" hash={ props.from.hash } truncation="constant"/>
<AddressLink fontWeight="500" hash={ from.hash } truncation="constant"/>
<Icon as={ rightArrowIcon } boxSize={ 6 } mx={ 2 } color="gray.500"/>
<AddressLink fontWeight="500" hash={ props.to.hash } truncation="constant"/>
<AddressLink fontWeight="500" hash={ to.hash } truncation="constant"/>
</Flex>
<Flex flexDir="column" rowGap={ 5 }>
{ content }
......
......@@ -10,9 +10,9 @@ interface Props {
}
function getItemsNum(items: Array<TTokenTransfer>) {
const nonErc1155items = items.filter((item) => item.token_type !== 'ERC-1155').length;
const nonErc1155items = items.filter((item) => item.token.type !== 'ERC-1155').length;
const erc1155items = items
.filter((item) => item.token_type === 'ERC-1155')
.filter((item) => item.token.type === 'ERC-1155')
.map((item) => {
if (Array.isArray(item.total)) {
return item.total.length;
......
import { Grid, GridItem, Text, Box, Icon, Link, Spinner } from '@chakra-ui/react';
import { Grid, GridItem, Text, Box, Icon, Link, Spinner, Tag, Flex, Tooltip, chakra } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import BigNumber from 'bignumber.js';
import { useRouter } from 'next/router';
......@@ -11,9 +11,9 @@ import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config';
import clockIcon from 'icons/clock.svg';
import flameIcon from 'icons/flame.svg';
import errorIcon from 'icons/status/error.svg';
import successIcon from 'icons/status/success.svg';
import { WEI, WEI_IN_GWEI } from 'lib/consts';
// import errorIcon from 'icons/status/error.svg';
// import successIcon from 'icons/status/success.svg';
import dayjs from 'lib/date/dayjs';
import useFetch from 'lib/hooks/useFetch';
import getConfirmationDuration from 'lib/tx/getConfirmationDuration';
......@@ -73,6 +73,18 @@ const TxDetails = () => {
return <DataFetchAlert/>;
}
const addressFromTags = [
...data.from.private_tags || [],
...data.from.public_tags || [],
...data.from.watchlist_names || [],
].map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
const addressToTags = [
...data.to.private_tags || [],
...data.to.public_tags || [],
...data.to.watchlist_names || [],
].map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
return (
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}>
<DetailsInfoItem
......@@ -132,36 +144,51 @@ const TxDetails = () => {
<DetailsInfoItem
title="From"
hint="Address (external or contract) sending the transaction."
columnGap={ 3 }
>
<Address>
<AddressIcon hash={ data.from.hash }/>
<AddressLink ml={ 2 } hash={ data.from.hash } alias={ data.from.name }/>
<AddressLink ml={ 2 } hash={ data.from.hash }/>
<CopyToClipboard text={ data.from.hash }/>
</Address>
{ data.from.name && <Text>{ data.from.name }</Text> }
{ addressFromTags.length > 0 && (
<Flex columnGap={ 3 }>
{ addressFromTags }
</Flex>
) }
</DetailsInfoItem>
<DetailsInfoItem
title={ data.to.is_contract ? 'Interacted with contract' : 'To' }
hint="Address (external or contract) receiving the transaction."
flexWrap={{ base: 'wrap', lg: 'nowrap' }}
columnGap={ 3 }
>
<Address mr={ 3 }>
<Address>
<AddressIcon hash={ data.to.hash }/>
<AddressLink ml={ 2 } hash={ data.to.hash } alias={ data.to.name }/>
<AddressLink ml={ 2 } hash={ data.to.hash }/>
<CopyToClipboard text={ data.to.hash }/>
</Address>
{ /* todo_tom Nikita should add to api later */ }
{ /* <Tag colorScheme="orange" variant="solid" flexShrink={ 0 }>SANA</Tag> */ }
{ /* <Tooltip label="Contract execution completed">
<chakra.span display="inline-flex">
<Icon as={ successIcon } boxSize={ 4 } ml={ 2 } color="green.500" cursor="pointer"/>
</chakra.span>
</Tooltip> */ }
{ /* <Tooltip label="Error occured during contract execution">
<chakra.span display="inline-flex">
<Icon as={ errorIcon } boxSize={ 4 } ml={ 2 } color="red.500" cursor="pointer"/>
</chakra.span>
</Tooltip> */ }
{ /* <TokenSnippet symbol="UP" name="User Pay" hash="0xA17ed5dFc62D0a3E74D69a0503AE9FdA65d9f212" ml={ 3 }/> */ }
{ data.to.name && <Text>{ data.to.name }</Text> }
{ data.to.is_contract && data.result === 'success' && (
<Tooltip label="Contract execution completed">
<chakra.span display="inline-flex">
<Icon as={ successIcon } boxSize={ 4 } color="green.500" cursor="pointer"/>
</chakra.span>
</Tooltip>
) }
{ data.to.is_contract && Boolean(data.status) && data.result !== 'success' && (
<Tooltip label="Error occured during contract execution">
<chakra.span display="inline-flex">
<Icon as={ errorIcon } boxSize={ 4 } color="red.500" cursor="pointer"/>
</chakra.span>
</Tooltip>
) }
{ addressToTags.length > 0 && (
<Flex columnGap={ 3 }>
{ addressToTags }
</Flex>
) }
</DetailsInfoItem>
{ TOKEN_TRANSFERS.map(({ title, hint, type }) => {
const items = data.token_transfers?.filter((token) => token.type === type) || [];
......
......@@ -43,16 +43,15 @@ const sortFn = (sort: Sort | undefined) => (a: InternalTransaction, b: InternalT
return a.value === b.value ? 0 : result;
}
// no gas limit in api yet
// case 'gas-limit-desc': {
// const result = a.gasLimit > b.gasLimit ? -1 : 1;
// return a.gasLimit === b.gasLimit ? 0 : result;
// }
// case 'gas-limit-asc': {
// const result = a.gasLimit > b.gasLimit ? 1 : -1;
// return a.gasLimit === b.gasLimit ? 0 : result;
// }
case 'gas-limit-desc': {
const result = a.gas_limit > b.gas_limit ? -1 : 1;
return a.gas_limit === b.gas_limit ? 0 : result;
}
case 'gas-limit-asc': {
const result = a.gas_limit > b.gas_limit ? 1 : -1;
return a.gas_limit === b.gas_limit ? 0 : result;
}
default:
return 0;
......
import { Flex, Tag, Icon, Box, HStack, Text } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction';
......@@ -14,7 +15,7 @@ import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction;
const TxInternalsListItem = ({ type, from, to, value, success, error }: Props) => {
const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit: gasLimit }: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
return (
......@@ -38,11 +39,10 @@ const TxInternalsListItem = ({ type, from, to, value, success, error }: Props) =
<Text fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Text>
<Text fontSize="sm" variant="secondary">{ value }</Text>
</HStack>
{ /* no gas limit in api yet */ }
{ /* <HStack spacing={ 3 }>
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Gas limit</Text>
<Text fontSize="sm" variant="secondary">{ gasLimit.toLocaleString('en') }</Text>
</HStack> */ }
<Text fontSize="sm" variant="secondary">{ BigNumber(gasLimit).toFormat() }</Text>
</HStack>
</AccountListItemMobile>
);
};
......
......@@ -10,7 +10,7 @@ const TxInternalsSkeletonDesktop = () => {
<Skeleton w="78px"/>
<Skeleton w="360px"/>
</Flex>
<SkeletonTable columns={ [ '28%', '28%', '24px', '28%', '16%' ] }/>
<SkeletonTable columns={ [ '28%', '20%', '24px', '20%', '16%', '16%' ] }/>
</>
);
};
......
......@@ -38,6 +38,10 @@ const TxInternalsSkeletonMobile = () => {
<Skeleton w="70px" mr={ 2 }/>
<Skeleton w="30px"/>
</Flex>
<Flex h={ 6 }>
<Skeleton w="70px" mr={ 2 }/>
<Skeleton w="60px"/>
</Flex>
</Flex>
)) }
</Box>
......
......@@ -23,22 +23,21 @@ const TxInternalsTable = ({ data, sort, onSortToggle }: Props) => {
<Thead>
<Tr>
<Th width="28%">Type</Th>
<Th width="28%">From</Th>
<Th width="20%">From</Th>
<Th width="24px" px={ 0 }/>
<Th width="28%">To</Th>
<Th width="20%">To</Th>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('value') } columnGap={ 1 }>
{ sort?.includes('value') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Value { appConfig.network.currency.symbol }
</Link>
</Th>
{ /* no gas limit in api yet */ }
{ /* <Th width="16%" isNumeric>
<Th width="16%" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('gas-limit') } columnGap={ 1 }>
{ sort?.includes('gas-limit') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Gas limit
Gas limit { appConfig.network.currency.symbol }
</Link>
</Th> */ }
</Th>
</Tr>
</Thead>
<Tbody>
......
import { Tr, Td, Tag, Icon, Box } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction';
......@@ -12,7 +13,7 @@ import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction
const TxInternalTableItem = ({ type, from, to, value, success, error }: Props) => {
const TxInternalTableItem = ({ type, from, to, value, success, error, gas_limit: gasLimit }: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
return (
......@@ -43,10 +44,9 @@ const TxInternalTableItem = ({ type, from, to, value, success, error }: Props) =
<Td isNumeric verticalAlign="middle">
{ value }
</Td>
{ /* no gas limit in api yet */ }
{ /* <Td isNumeric verticalAlign='middle'>
{ gasLimit.toLocaleString('en') }
</Td> */ }
<Td isNumeric verticalAlign="middle">
{ BigNumber(gasLimit).toFormat() }
</Td>
</Tr>
);
};
......
......@@ -60,6 +60,7 @@ const TxsListItem = ({ tx }: {tx: Transaction}) => {
type="transaction"
fontWeight="700"
truncation="constant"
target="_self"
/>
</Address>
</Flex>
......
......@@ -86,6 +86,7 @@ const TxsTableItem = ({ tx }: {tx: Transaction}) => {
hash={ tx.hash }
type="transaction"
fontWeight="700"
target="_self"
/>
</Address>
<Text color="gray.500" fontWeight="400">{ dayjs(tx.timestamp).fromNow() }</Text>
......
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