Commit 72ae4ea7 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #231 from blockscout/tx-revert-reason

tx revert reason
parents 00c7792b a313fd7e
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.868 1.55a.377.377 0 0 0-.378 0L3.188 6.363A.377.377 0 0 0 3 6.69v9.622c0 .135.072.26.188.327l8.302 4.811a.377.377 0 0 0 .378 0l8.302-4.811a.377.377 0 0 0 .188-.327V6.69a.377.377 0 0 0-.188-.327l-8.302-4.811ZM3.755 16.095V6.906l7.924-4.592 7.925 4.592v9.188l-7.925 4.592-7.924-4.592ZM8.66 6.972a.377.377 0 0 0-.754 0v6.354l-1.53-4.587a.377.377 0 0 0-.734.12v5.66a.377.377 0 0 0 .754 0v-3.335l1.529 4.586a.377.377 0 0 0 .735-.12V6.973Zm2.824-2.448a.377.377 0 0 1 .386-.003l2.262 1.32a.377.377 0 0 1-.38.652l-2.07-1.208-1.89 1.145v4.693h2.265a.377.377 0 0 1 0 .754H9.792v4.906a.377.377 0 0 1-.754 0V6.217c0-.132.069-.254.182-.323l2.264-1.37Zm3.195 2.06a.377.377 0 0 1 .515-.141l2.333 1.333a.377.377 0 1 1-.375.655l-.567-.324v7.544a.377.377 0 1 1-.755 0V7.676l-1.01-.578a.377.377 0 0 1-.141-.515Z" fill="currentColor"/>
</svg>
......@@ -13,7 +13,8 @@ const paths = {
blocks: `${ BASE_PATH }/blocks`,
block: `${ BASE_PATH }/block/[id]`,
tokens: `${ BASE_PATH }/tokens`,
token_index: `${ BASE_PATH }/token/[id]`,
token_index: `${ BASE_PATH }/token/[hash]`,
token_instance_item: `${ BASE_PATH }/token/[hash]/instance/[id]`,
address_index: `${ BASE_PATH }/address/[id]`,
address_contract_verification: `${ BASE_PATH }/address/[id]/contract_verifications/new`,
apps: `${ BASE_PATH }/apps`,
......
......@@ -63,6 +63,9 @@ export const ROUTES = {
pattern: PATHS.token_index,
crossNetworkNavigation: true,
},
token_instance_item: {
pattern: PATHS.token_instance_item,
},
// ADDRESSES
address_index: {
......
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
const baseStyle = defineStyle((props) => {
const { emptyColor, color } = props;
return {
borderColor: color || 'blue.500',
borderBottomColor: emptyColor || mode('blackAlpha.200', 'whiteAlpha.200')(props),
borderLeftColor: emptyColor || mode('blackAlpha.200', 'whiteAlpha.200')(props),
};
});
const Spinner = defineStyleConfig({
baseStyle,
defaultProps: {
size: 'md',
},
});
export default Spinner;
......@@ -12,6 +12,7 @@ import Modal from './Modal';
import Popover from './Popover';
import Radio from './Radio';
import Skeleton from './Skeleton';
import Spinner from './Spinner';
import Table from './Table';
import Tabs from './Tabs';
import Tag from './Tag';
......@@ -34,6 +35,7 @@ const components = {
Popover,
Radio,
Skeleton,
Spinner,
Tabs,
Table,
Tag,
......
import type { AddressParam } from './addressParams';
export interface TokenTransfer {
type: string;
export type ERC1155TotalPayload = {
value: string;
token_id: string;
}
export type TokenTransfer = (
{
token_type: 'ERC-20';
total: {
value: string;
};
} |
{
token_type: 'ERC-721';
total: {
token_id: string;
};
} |
{
token_type: 'ERC-1155';
total: ERC1155TotalPayload | Array<ERC1155TotalPayload>;
}
) & TokenTransferBase
interface TokenTransferBase {
type: 'token_transfer' | 'token_burning' | 'token_spawning' | 'token_minting';
txHash: string;
from: AddressParam;
to: AddressParam;
token_address: string;
token_symbol: string;
token_type: string;
total: {
value: string;
};
exchange_rate: string;
}
......@@ -3,13 +3,18 @@ import type { DecodedInput } from './decodedInput';
import type { Fee } from './fee';
import type { TokenTransfer } from './tokenTransfer';
export type TransactionRevertReason = {
raw: string;
decoded: string;
} | DecodedInput;
export interface Transaction {
hash: string;
result: string;
confirmations: number;
status: 'ok' | 'error' | null;
block: number | null;
timestamp: string;
timestamp: string | null;
confirmation_duration: Array<number>;
from: AddressParam;
to: AddressParam;
......@@ -18,7 +23,7 @@ export interface Transaction {
fee: Fee;
gas_price: number;
type: number;
gas_used: string;
gas_used: string | null;
gas_limit: string;
max_fee_per_gas: number | null;
max_priority_fee_per_gas: number | null;
......@@ -27,10 +32,7 @@ export interface Transaction {
tx_burnt_fee: number | null;
nonce: number;
position: number;
revert_reason: {
raw: string;
decoded: string;
} | null;
revert_reason: TransactionRevertReason | null;
raw_input: string;
decoded_input: DecodedInput | null;
token_transfers: Array<TokenTransfer> | null;
......
......@@ -17,13 +17,11 @@ interface Props {
}
const BlocksTableItem = ({ data, isPending }: Props) => {
const spinnerEmptyColor = useColorModeValue('blackAlpha.200', 'whiteAlpha.200');
return (
<Tr>
<Td fontSize="sm">
<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) }) }
......
......@@ -33,12 +33,12 @@ const CurrencyValue = ({ value, currency = '', unit, exchangeRate, className, ac
}
usdContent = (
<Text as="span" variant="secondary" whiteSpace="pre" fontWeight={ 400 }> (${ usdResult })</Text>
<Text as="span" variant="secondary" fontWeight={ 400 }>(${ usdResult })</Text>
);
}
return (
<Box as="span" className={ className }>
<Box as="span" className={ className } display="inline-flex" rowGap={ 3 } columnGap={ 1 }>
<Text display="inline-block">
{ valueResult }{ currency ? ` ${ currency }` : '' }
</Text>
......
......@@ -12,7 +12,7 @@ interface Props {
}
const TokenSnippet = ({ symbol, hash, name, className }: Props) => {
const url = link('token_index', { id: hash });
const url = link('token_index', { hash });
return (
<Center className={ className } columnGap={ 1 }>
......
......@@ -20,7 +20,7 @@ const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id,
if (type === 'transaction') {
url = link('tx', { id: id || hash });
} else if (type === 'token') {
url = link('token_index', { id: id || hash });
url = link('token_index', { hash: id || hash });
} else if (type === 'block') {
url = link('block', { id: id || hash });
} else {
......
import { Flex, Link, Text, Icon, Box } from '@chakra-ui/react';
import React from 'react';
import nftIcon from 'icons/nft_shield.svg';
import link from 'lib/link/link';
import TokenSnippet from 'ui/shared/TokenSnippet';
interface Props {
value: string;
tokenId: string;
hash: string;
symbol: string;
}
const NftTokenTransferSnippet = (props: Props) => {
const num = props.value === '1' ? '' : props.value;
const url = link('token_instance_item', { hash: props.hash, id: props.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>
</Box>
<TokenSnippet symbol={ props.symbol } hash={ props.hash } name="Foo"/>
</Flex>
);
};
export default React.memo(NftTokenTransferSnippet);
......@@ -8,23 +8,71 @@ import { space } from 'lib/html-entities';
import AddressLink from 'ui/shared/address/AddressLink';
import CurrencyValue from 'ui/shared/CurrencyValue';
import TokenSnippet from 'ui/shared/TokenSnippet';
import NftTokenTransferSnippet from 'ui/tx/NftTokenTransferSnippet';
type Props = TTokenTransfer
type Props = TTokenTransfer;
const TokenTransfer = ({ from, to, total, exchange_rate: exchangeRate, ...token }: Props) => {
const TokenTransfer = (props: 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 content = (() => {
switch (props.token_type) {
case 'ERC-20':
return (
<Flex>
<Text fontWeight={ 500 } as="span">For:{ space }
<CurrencyValue value={ props.total.value } unit="ether" exchangeRate={ props.exchange_rate } fontWeight={ 600 }/>
</Text>
{ tokenSnippet }
</Flex>
);
case 'ERC-721': {
return (
<Flex alignItems="center" flexWrap="wrap" columnGap={ 3 } rowGap={ 3 }>
<NftTokenTransferSnippet
tokenId={ props.total.token_id }
value="1"
hash={ props.token_address }
symbol={ props.token_symbol }
/>
);
}
case 'ERC-1155': {
const items = Array.isArray(props.total) ? props.total : [ props.total ];
return items.map((item) => (
<NftTokenTransferSnippet
key={ item.token_id }
tokenId={ item.token_id }
value={ item.value }
hash={ props.token_address }
symbol={ props.token_symbol }
/>
));
}
}
})();
return (
<Flex
alignItems={ isColumnLayout ? 'flex-start' : 'center' }
flexWrap="wrap"
columnGap={ 3 }
rowGap={ 3 }
flexDir={ isColumnLayout ? 'column' : 'row' }
>
<Flex alignItems="center">
<AddressLink fontWeight="500" hash={ from.hash } truncation="constant"/>
<AddressLink fontWeight="500" hash={ props.from.hash } truncation="constant"/>
<Icon as={ rightArrowIcon } boxSize={ 6 } mx={ 2 } color="gray.500"/>
<AddressLink fontWeight="500" hash={ to.hash } truncation="constant"/>
<AddressLink fontWeight="500" hash={ props.to.hash } truncation="constant"/>
</Flex>
<Flex flexDir="column" rowGap={ 5 }>
{ content }
</Flex>
<Text fontWeight={ 500 } as="span">For:{ space }
<CurrencyValue value={ total.value.replaceAll(',', '') } unit="ether" exchangeRate={ exchangeRate } fontWeight={ 600 }/>
</Text>
<TokenSnippet symbol={ token.token_symbol } hash={ token.token_address } name="Foo"/>
</Flex>
);
};
export default TokenTransfer;
export default React.memo(TokenTransfer);
import { Flex, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { TokenTransfer as TTokenTransfer } from 'types/api/tokenTransfer';
import TokenTransfer from 'ui/tx/TokenTransfer';
interface Props {
items: Array<TTokenTransfer>;
}
function getItemsNum(items: Array<TTokenTransfer>) {
const nonErc1155items = items.filter((item) => item.token_type !== 'ERC-1155').length;
const erc1155items = items
.filter((item) => item.token_type === 'ERC-1155')
.map((item) => {
if (Array.isArray(item.total)) {
return item.total.length;
}
return 1;
})
.reduce((sum, item) => sum + item, 0);
return nonErc1155items + erc1155items;
}
const TokenTransferList = ({ items }: Props) => {
const itemsNum = getItemsNum(items);
const hasScroll = itemsNum > 5;
const gradientStartColor = useColorModeValue('whiteAlpha.600', 'blackAlpha.600');
const gradientEndColor = useColorModeValue('whiteAlpha.900', 'blackAlpha.900');
return (
<Flex
flexDirection="column"
alignItems="flex-start"
rowGap={ 5 }
w="100%"
_after={ hasScroll ? {
position: 'absolute',
content: '""',
bottom: 0,
left: 0,
right: '20px',
height: '48px',
bgGradient: `linear(to-b, ${ gradientStartColor } 37.5%, ${ gradientEndColor } 77.5%)`,
} : undefined }
maxH={ hasScroll ? '200px' : 'auto' }
overflowY={ hasScroll ? 'scroll' : 'auto' }
pr={ hasScroll ? 5 : 0 }
pb={ hasScroll ? 10 : 0 }
>
{ items.map((item, index) => <TokenTransfer key={ index } { ...item }/>) }
</Flex>
);
};
export default React.memo(TokenTransferList);
......@@ -111,6 +111,8 @@ const TxDecodedInputData = ({ data }: Props) => {
{ data.method_call }
</GridItem>
{ /* TABLE INSIDE OF BLOCK */ }
{ data.parameters.length > 0 && (
<>
<GridItem
pl={ PADDING }
pr={ GAP }
......@@ -150,6 +152,8 @@ const TxDecodedInputData = ({ data }: Props) => {
>
Data
</GridItem>
</>
) }
{ data.parameters.map(({ name, type, value, indexed }, index) => {
return (
<TableRow key={ name } name={ name } type={ type } isLast={ index === data.parameters.length - 1 } indexed={ indexed }>
......@@ -160,7 +164,7 @@ const TxDecodedInputData = ({ data }: Props) => {
</Address>
) : (
<Flex alignItems="flex-start" justifyContent="space-between" whiteSpace="normal" wordBreak="break-all">
<Text>{ value }</Text>
<Text>{ String(value) }</Text>
<CopyToClipboard text={ value }/>
</Flex>
) }
......
import { Grid, GridItem, Text, Box, Icon, Link, Flex } from '@chakra-ui/react';
import { Grid, GridItem, Text, Box, Icon, Link, Spinner } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import BigNumber from 'bignumber.js';
import appConfig from 'configs/app/config';
......@@ -31,9 +31,17 @@ import TextSeparator from 'ui/shared/TextSeparator';
import TxStatus from 'ui/shared/TxStatus';
import Utilization from 'ui/shared/Utilization';
import TxDetailsSkeleton from 'ui/tx/details/TxDetailsSkeleton';
import TokenTransfer from 'ui/tx/TokenTransfer';
import TxRevertReason from 'ui/tx/details/TxRevertReason';
import TokenTransferList from 'ui/tx/TokenTransferList';
import TxDecodedInputData from 'ui/tx/TxDecodedInputData';
const TOKEN_TRANSFERS = [
{ title: 'Tokens Transferred', hint: 'List of tokens transferred in the transaction.', type: 'token_transfer' },
{ title: 'Tokens Minted', hint: 'List of tokens minted in the transaction.', type: 'token_minting' },
{ title: 'Tokens Burnt', hint: 'List of tokens burnt in the transaction.', type: 'token_burning' },
{ title: 'Tokens Created', hint: 'List of tokens created in the transaction.', type: 'token_spawning' },
];
const TxDetails = () => {
const router = useRouter();
const fetch = useFetch();
......@@ -71,6 +79,7 @@ const TxDetails = () => {
hint="Unique character string (TxID) assigned to every verified transaction."
flexWrap="nowrap"
>
{ data.status === null && <Spinner mr={ 2 } size="sm" flexShrink={ 0 }/> }
<Box overflow="hidden">
<HashStringShortenDynamic hash={ data.hash }/>
</Box>
......@@ -83,16 +92,29 @@ const TxDetails = () => {
>
<TxStatus status={ data.status } errorText={ data.status === 'error' ? data.result : undefined }/>
</DetailsInfoItem>
{ data.revert_reason && (
<DetailsInfoItem
title="Revert reason"
hint="The revert reason of the transaction."
>
<TxRevertReason { ...data.revert_reason }/>
</DetailsInfoItem>
) }
<DetailsInfoItem
title="Block"
hint="Block number containing the transaction."
>
<Text>{ data.block }</Text>
<Text>{ data.block === null ? 'Pending' : data.block }</Text>
{ Boolean(data.confirmations) && (
<>
<TextSeparator color="gray.500"/>
<Text variant="secondary">
{ data.confirmations } Block confirmations
</Text>
</>
) }
</DetailsInfoItem>
{ data.timestamp && (
<DetailsInfoItem
title="Timestamp"
hint="Date & time of transaction inclusion, including length of time for confirmation."
......@@ -103,6 +125,7 @@ const TxDetails = () => {
<Text whiteSpace="normal">{ dayjs(data.timestamp).format('LLLL') }<TextSeparator color="gray.500"/></Text>
<Text variant="secondary">{ getConfirmationDuration(data.confirmation_duration) }</Text>
</DetailsInfoItem>
) }
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 3, lg: 8 }}/>
<DetailsInfoItem
title="From"
......@@ -138,16 +161,23 @@ const TxDetails = () => {
</Tooltip> */ }
{ /* <TokenSnippet symbol="UP" name="User Pay" hash="0xA17ed5dFc62D0a3E74D69a0503AE9FdA65d9f212" ml={ 3 }/> */ }
</DetailsInfoItem>
{ (data.token_transfers?.length || 0) > 0 && (
{ TOKEN_TRANSFERS.map(({ title, hint, type }) => {
const items = data.token_transfers?.filter((token) => token.type === type) || [];
if (items.length === 0) {
return null;
}
return (
<DetailsInfoItem
title="Token transferred"
hint="List of token transferred in the transaction."
key={ type }
title={ title }
hint={ hint }
position="relative"
>
<Flex flexDirection="column" alignItems="flex-start" rowGap={ 5 } w="100%">
{ data.token_transfers?.map((item, index) => <TokenTransfer key={ index } { ...item }/>) }
</Flex>
<TokenTransferList items={ items }/>
</DetailsInfoItem>
) }
);
}) }
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 3, lg: 8 }}/>
<DetailsInfoItem
title="Value"
......@@ -159,7 +189,12 @@ const TxDetails = () => {
title="Transaction fee"
hint="Total transaction fee."
>
<CurrencyValue value={ data.fee.value } currency={ appConfig.network.currency } exchangeRate={ data.exchange_rate }/>
<CurrencyValue
value={ data.fee.value }
currency={ appConfig.network.currency }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
/>
</DetailsInfoItem>
<DetailsInfoItem
title="Gas price"
......@@ -172,10 +207,10 @@ const TxDetails = () => {
title="Gas limit & usage by txn"
hint="Actual gas amount used by the transaction."
>
<Text>{ BigNumber(data.gas_used).toFormat() }</Text>
<Text>{ BigNumber(data.gas_used || 0).toFormat() }</Text>
<TextSeparator/>
<Text >{ BigNumber(data.gas_limit).toFormat() }</Text>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used).dividedBy(BigNumber(data.gas_limit)).toNumber() }/>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() }/>
</DetailsInfoItem>
{ (data.base_fee_per_gas || data.max_fee_per_gas || data.max_priority_fee_per_gas) && (
<DetailsInfoItem
......@@ -187,18 +222,18 @@ const TxDetails = () => {
<Box>
<Text as="span" fontWeight="500">Base: </Text>
<Text fontWeight="600" as="span">{ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
{ (data.max_fee_per_gas || data.max_priority_fee_per_gas) && <TextSeparator/> }
</Box>
) }
{ data.max_fee_per_gas && (
<Box>
<TextSeparator/>
<Text as="span" fontWeight="500">Max: </Text>
<Text fontWeight="600" as="span">{ BigNumber(data.max_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
{ data.max_priority_fee_per_gas && <TextSeparator/> }
</Box>
) }
{ data.max_priority_fee_per_gas && (
<Box>
<TextSeparator/>
<Text as="span" fontWeight="500">Max priority: </Text>
<Text fontWeight="600" as="span">{ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
</Box>
......@@ -211,7 +246,12 @@ const TxDetails = () => {
hint={ `Amount of ${ appConfig.network.currency } burned for this transaction. Equals Block Base Fee per Gas * Gas Used.` }
>
<Icon as={ flameIcon } mr={ 1 } boxSize={ 5 } color="gray.500"/>
<CurrencyValue value={ String(data.tx_burnt_fee) } currency={ appConfig.network.currency } exchangeRate={ data.exchange_rate }/>
<CurrencyValue
value={ String(data.tx_burnt_fee) }
currency={ appConfig.network.currency }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
/>
</DetailsInfoItem>
) }
<GridItem colSpan={{ base: undefined, lg: 2 }}>
......@@ -235,23 +275,34 @@ const TxDetails = () => {
title="Other"
hint="Other data related to this transaction."
>
{ typeof data.type === 'number' && (
<Box>
{
[
typeof data.type === 'number' && (
<Box key="type">
<Text as="span" fontWeight="500">Txn type: </Text>
<Text fontWeight="600" as="span">{ data.type }</Text>
{ data.type === 2 && <Text fontWeight="400" as="span" ml={ 1 } variant="secondary">(EIP-1559)</Text> }
<TextSeparator/>
</Box>
) }
<Box>
),
<Box key="nonce">
<Text as="span" fontWeight="500">Nonce: </Text>
<Text fontWeight="600" as="span">{ data.nonce }</Text>
<TextSeparator/>
</Box>
<Box>
</Box>,
data.position !== null && (
<Box key="position">
<Text as="span" fontWeight="500">Position: </Text>
<Text fontWeight="600" as="span">{ data.position }</Text>
</Box>
),
]
.filter(Boolean)
.map((item, index) => (
<>
{ index !== 0 && <TextSeparator/> }
{ item }
</>
))
}
</DetailsInfoItem>
<DetailsInfoItem
title="Raw input"
......
import { Grid, GridItem, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { TransactionRevertReason } from 'types/api/transaction';
import TxDecodedInputData from 'ui/tx/TxDecodedInputData';
type Props = TransactionRevertReason;
const TxRevertReason = (props: Props) => {
const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
if ('raw' in props) {
return (
<Grid
bgColor={ bgColor }
p={ 4 }
fontSize="sm"
borderRadius="md"
templateColumns="auto minmax(0, 1fr)"
rowGap={ 2 }
columnGap={ 4 }
whiteSpace="normal"
>
<GridItem fontWeight={ 500 }>Raw:</GridItem>
<GridItem>{ props.raw }</GridItem>
<GridItem fontWeight={ 500 }>Decoded:</GridItem>
<GridItem>{ props.decoded }</GridItem>
</Grid>
);
}
return <TxDecodedInputData data={ props }/>;
};
export default React.memo(TxRevertReason);
......@@ -26,7 +26,7 @@ const TxInternalTableItem = ({ type, from, to, value, success, error }: Props) =
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error }/>
</Td>
<Td>
<Address>
<Address display="inline-flex" maxW="100%">
<AddressIcon hash={ from.hash }/>
<AddressLink ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.name } flexGrow={ 1 }/>
</Address>
......@@ -35,16 +35,16 @@ const TxInternalTableItem = ({ type, from, to, value, success, error }: Props) =
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500"/>
</Td>
<Td>
<Address>
<Address display="inline-flex" maxW="100%">
<AddressIcon hash={ to.hash }/>
<AddressLink hash={ to.hash } alias={ to.name } fontWeight="500" ml={ 2 }/>
</Address>
</Td>
<Td isNumeric>
<Td isNumeric verticalAlign="middle">
{ value }
</Td>
{ /* no gas limit in api yet */ }
{ /* <Td isNumeric>
{ /* <Td isNumeric verticalAlign='middle'>
{ gasLimit.toLocaleString('en') }
</Td> */ }
</Tr>
......
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