Commit cc4885d8 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #855 from blockscout/tx-upd

tx: testnet warning and method badge
parents 6015bb72 b2f0cb6b
...@@ -167,3 +167,28 @@ l2Test('l2', async({ mount, page }) => { ...@@ -167,3 +167,28 @@ l2Test('l2', async({ mount, page }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
const mainnetTest = test.extend({
context: contextWithEnvs([
{ name: 'NEXT_PUBLIC_IS_TESTNET', value: 'false' },
// eslint-disable-next-line @typescript-eslint/no-explicit-any
]) as any,
});
mainnetTest('without testnet warning', async({ mount, page }) => {
await page.route(API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(txMock.l2tx),
}));
const component = await mount(
<TestApp>
<TxDetails/>
</TestApp>,
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
...@@ -6,12 +6,12 @@ import { ...@@ -6,12 +6,12 @@ import {
Icon as ChakraIcon, Icon as ChakraIcon,
Link, Link,
Spinner, Spinner,
Tag,
Flex, Flex,
Tooltip, Tooltip,
chakra, chakra,
useColorModeValue, useColorModeValue,
Skeleton, Skeleton,
Alert,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
...@@ -30,6 +30,7 @@ import Address from 'ui/shared/address/Address'; ...@@ -30,6 +30,7 @@ import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
...@@ -120,350 +121,363 @@ const TxDetails = () => { ...@@ -120,350 +121,363 @@ const TxDetails = () => {
); );
return ( return (
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}> <>
{ socketStatus && ( { appConfig.network.isTestnet && <Alert status="warning" mb={ 6 }>This is a { appConfig.network.name } testnet transaction only</Alert> }
<GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }> <Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}>
<TxSocketAlert status={ socketStatus }/> { socketStatus && (
</GridItem> <GridItem colSpan={{ base: undefined, lg: 2 }} mb={ 2 }>
) } <TxSocketAlert status={ socketStatus }/>
<DetailsInfoItem </GridItem>
title="Transaction hash" ) }
hint="Unique character string (TxID) assigned to every verified transaction"
flexWrap="nowrap"
isLoading={ isPlaceholderData }
>
{ data.status === null && <Spinner mr={ 2 } size="sm" flexShrink={ 0 }/> }
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
<HashStringShortenDynamic hash={ data.hash }/>
</Skeleton>
<CopyToClipboard text={ data.hash } isLoading={ isPlaceholderData }/>
{ /* api doesn't support navigation between certain address account tx */ }
{ /* <PrevNext ml={ 7 }/> */ }
</DetailsInfoItem>
<DetailsInfoItem
title="Status"
hint="Current transaction state: Success, Failed (Error), or Pending (In Process)"
isLoading={ isPlaceholderData }
>
<TxStatus status={ data.status } errorText={ data.status === 'error' ? data.result : undefined } isLoading={ isPlaceholderData }/>
</DetailsInfoItem>
{ data.revert_reason && (
<DetailsInfoItem <DetailsInfoItem
title="Revert reason" title="Transaction hash"
hint="The revert reason of the transaction" hint="Unique character string (TxID) assigned to every verified transaction"
flexWrap="nowrap"
isLoading={ isPlaceholderData }
> >
<TxRevertReason { ...data.revert_reason }/> { data.status === null && <Spinner mr={ 2 } size="sm" flexShrink={ 0 }/> }
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
<HashStringShortenDynamic hash={ data.hash }/>
</Skeleton>
<CopyToClipboard text={ data.hash } isLoading={ isPlaceholderData }/>
{ /* api doesn't support navigation between certain address account tx */ }
{ /* <PrevNext ml={ 7 }/> */ }
</DetailsInfoItem> </DetailsInfoItem>
) } <DetailsInfoItem
<DetailsInfoItem title="Status and method"
title="Block" hint="Current transaction state: Success, Failed (Error), or Pending (In Process)"
hint="Block number containing the transaction" isLoading={ isPlaceholderData }
isLoading={ isPlaceholderData } >
> <TxStatus status={ data.status } errorText={ data.status === 'error' ? data.result : undefined } isLoading={ isPlaceholderData }/>
{ data.block === null ? { data.method && (
<Text>Pending</Text> : ( <Tag colorScheme={ data.method === 'Multicall' ? 'teal' : 'gray' } isLoading={ isPlaceholderData } isTruncated ml={ 3 }>
<Skeleton isLoaded={ !isPlaceholderData }> { data.method }
<LinkInternal href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.block) } }) }> </Tag>
{ data.block }
</LinkInternal>
</Skeleton>
) } ) }
{ Boolean(data.confirmations) && ( </DetailsInfoItem>
<> { data.revert_reason && (
<TextSeparator color="gray.500"/> <DetailsInfoItem
<Skeleton isLoaded={ !isPlaceholderData } color="text_secondary"> title="Revert reason"
<span>{ data.confirmations } Block confirmations</span> hint="The revert reason of the transaction"
</Skeleton> >
</> <TxRevertReason { ...data.revert_reason }/>
</DetailsInfoItem>
) } ) }
</DetailsInfoItem>
{ data.timestamp && (
<DetailsInfoItem <DetailsInfoItem
title="Timestamp" title="Block"
hint="Date & time of transaction inclusion, including length of time for confirmation" hint="Block number containing the transaction"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
<Icon as={ clockIcon } boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/> { data.block === null ?
<Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }>{ dayjs(data.timestamp).fromNow() }</Skeleton> <Text>Pending</Text> : (
<TextSeparator/> <Skeleton isLoaded={ !isPlaceholderData }>
<Skeleton isLoaded={ !isPlaceholderData } whiteSpace="normal">{ dayjs(data.timestamp).format('LLLL') }</Skeleton> <LinkInternal href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(data.block) } }) }>
<TextSeparator color="gray.500"/> { data.block }
<Skeleton isLoaded={ !isPlaceholderData } color="text_secondary"> </LinkInternal>
<span>{ getConfirmationDuration(data.confirmation_duration) }</span> </Skeleton>
</Skeleton> ) }
{ Boolean(data.confirmations) && (
<>
<TextSeparator color="gray.500"/>
<Skeleton isLoaded={ !isPlaceholderData } color="text_secondary">
<span>{ data.confirmations } Block confirmations</span>
</Skeleton>
</>
) }
</DetailsInfoItem> </DetailsInfoItem>
) } { data.timestamp && (
<DetailsSponsoredItem isLoading={ isPlaceholderData }/> <DetailsInfoItem
title="Timestamp"
{ divider } hint="Date & time of transaction inclusion, including length of time for confirmation"
isLoading={ isPlaceholderData }
>
<Icon as={ clockIcon } boxSize={ 5 } color="gray.500" isLoading={ isPlaceholderData }/>
<Skeleton isLoaded={ !isPlaceholderData } ml={ 1 }>{ dayjs(data.timestamp).fromNow() }</Skeleton>
<TextSeparator/>
<Skeleton isLoaded={ !isPlaceholderData } whiteSpace="normal">{ dayjs(data.timestamp).format('LLLL') }</Skeleton>
<TextSeparator color="gray.500"/>
<Skeleton isLoaded={ !isPlaceholderData } color="text_secondary">
<span>{ getConfirmationDuration(data.confirmation_duration) }</span>
</Skeleton>
</DetailsInfoItem>
) }
<DetailsSponsoredItem isLoading={ isPlaceholderData }/>
{ actionsExist && ( { divider }
<>
<TxDetailsActions actions={ data.actions }/>
{ divider }
</>
) }
<DetailsInfoItem { actionsExist && (
title="From"
hint="Address (external or contract) sending the transaction"
isLoading={ isPlaceholderData }
columnGap={ 3 }
>
<Address>
<AddressIcon address={ data.from } isLoading={ isPlaceholderData }/>
<AddressLink type="address" ml={ 2 } hash={ data.from.hash } isLoading={ isPlaceholderData }/>
<CopyToClipboard text={ data.from.hash } isLoading={ isPlaceholderData }/>
</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"
isLoading={ isPlaceholderData }
flexWrap={{ base: 'wrap', lg: 'nowrap' }}
columnGap={ 3 }
>
{ toAddress ? (
<> <>
{ data.to && data.to.hash ? ( <TxDetailsActions actions={ data.actions }/>
<Address alignItems="center"> { divider }
<AddressIcon address={ toAddress } isLoading={ isPlaceholderData }/>
<AddressLink type="address" ml={ 2 } hash={ toAddress.hash } isLoading={ isPlaceholderData }/>
{ executionSuccessBadge }
{ executionFailedBadge }
<CopyToClipboard text={ toAddress.hash } isLoading={ isPlaceholderData }/>
</Address>
) : (
<Flex width={{ base: '100%', lg: 'auto' }} whiteSpace="pre" alignItems="center">
<span>[Contract </span>
<AddressLink type="address" hash={ toAddress.hash }/>
<span> created]</span>
{ executionSuccessBadge }
{ executionFailedBadge }
<CopyToClipboard text={ toAddress.hash }/>
</Flex>
) }
{ toAddress.name && <Text>{ toAddress.name }</Text> }
{ addressToTags.length > 0 && (
<Flex columnGap={ 3 }>
{ addressToTags }
</Flex>
) }
</> </>
) : (
<span>[ Contract creation ]</span>
) } ) }
</DetailsInfoItem>
{ data.token_transfers && <TxDetailsTokenTransfers data={ data.token_transfers } txHash={ data.hash }/> }
{ divider }
<DetailsInfoItem
title="Value"
hint="Value sent in the native token (and USD) if applicable"
isLoading={ isPlaceholderData }
>
<CurrencyValue value={ data.value } currency={ appConfig.network.currency.symbol } exchangeRate={ data.exchange_rate } isLoading={ isPlaceholderData }/>
</DetailsInfoItem>
<DetailsInfoItem
title="Transaction fee"
hint="Total transaction fee"
isLoading={ isPlaceholderData }
>
<CurrencyValue
value={ data.fee.value }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
isLoading={ isPlaceholderData }
/>
</DetailsInfoItem>
<DetailsInfoItem
title="Gas price"
hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage"
isLoading={ isPlaceholderData }
>
<Skeleton isLoaded={ !isPlaceholderData } mr={ 1 }>
{ BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
</Skeleton>
<Skeleton isLoaded={ !isPlaceholderData } color="text_secondary">
<span>({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</span>
</Skeleton>
</DetailsInfoItem>
<DetailsInfoItem
title="Gas usage & limit by txn"
hint="Actual gas amount used by the transaction"
isLoading={ isPlaceholderData }
>
<Skeleton isLoaded={ !isPlaceholderData }>{ BigNumber(data.gas_used || 0).toFormat() }</Skeleton>
<TextSeparator/>
<Skeleton isLoaded={ !isPlaceholderData }>{ BigNumber(data.gas_limit).toFormat() }</Skeleton>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() } isLoading={ isPlaceholderData }/>
</DetailsInfoItem>
{ (data.base_fee_per_gas || data.max_fee_per_gas || data.max_priority_fee_per_gas) && (
<DetailsInfoItem <DetailsInfoItem
title="Gas fees (Gwei)" title="From"
// eslint-disable-next-line max-len hint="Address (external or contract) sending the transaction"
hint="Base Fee refers to the network Base Fee at the time of the block, while Max Fee & Max Priority Fee refer to the max amount a user is willing to pay for their tx & to give to the miner respectively"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
columnGap={ 3 }
> >
{ data.base_fee_per_gas && ( <Address>
<Skeleton isLoaded={ !isPlaceholderData }> <AddressIcon address={ data.from } isLoading={ isPlaceholderData }/>
<Text as="span" fontWeight="500">Base: </Text> <AddressLink type="address" ml={ 2 } hash={ data.from.hash } isLoading={ isPlaceholderData }/>
<Text fontWeight="600" as="span">{ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text> <CopyToClipboard text={ data.from.hash } isLoading={ isPlaceholderData }/>
{ (data.max_fee_per_gas || data.max_priority_fee_per_gas) && <TextSeparator/> } </Address>
</Skeleton> { data.from.name && <Text>{ data.from.name }</Text> }
{ addressFromTags.length > 0 && (
<Flex columnGap={ 3 }>
{ addressFromTags }
</Flex>
) } ) }
{ data.max_fee_per_gas && ( </DetailsInfoItem>
<Box> <DetailsInfoItem
<Text as="span" fontWeight="500">Max: </Text> title={ data.to?.is_contract ? 'Interacted with contract' : 'To' }
<Text fontWeight="600" as="span">{ BigNumber(data.max_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text> hint="Address (external or contract) receiving the transaction"
{ data.max_priority_fee_per_gas && <TextSeparator/> } isLoading={ isPlaceholderData }
</Box> flexWrap={{ base: 'wrap', lg: 'nowrap' }}
) } columnGap={ 3 }
{ data.max_priority_fee_per_gas && ( >
<Box> { toAddress ? (
<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> { data.to && data.to.hash ? (
</Box> <Address alignItems="center">
<AddressIcon address={ toAddress } isLoading={ isPlaceholderData }/>
<AddressLink type="address" ml={ 2 } hash={ toAddress.hash } isLoading={ isPlaceholderData }/>
{ executionSuccessBadge }
{ executionFailedBadge }
<CopyToClipboard text={ toAddress.hash } isLoading={ isPlaceholderData }/>
</Address>
) : (
<Flex width={{ base: '100%', lg: 'auto' }} whiteSpace="pre" alignItems="center">
<span>[Contract </span>
<AddressLink type="address" hash={ toAddress.hash }/>
<span> created]</span>
{ executionSuccessBadge }
{ executionFailedBadge }
<CopyToClipboard text={ toAddress.hash }/>
</Flex>
) }
{ toAddress.name && <Text>{ toAddress.name }</Text> }
{ addressToTags.length > 0 && (
<Flex columnGap={ 3 }>
{ addressToTags }
</Flex>
) }
</>
) : (
<span>[ Contract creation ]</span>
) } ) }
</DetailsInfoItem> </DetailsInfoItem>
) } { data.token_transfers && <TxDetailsTokenTransfers data={ data.token_transfers } txHash={ data.hash }/> }
{ data.tx_burnt_fee && !appConfig.L2.isL2Network && (
{ divider }
<DetailsInfoItem
title="Value"
hint="Value sent in the native token (and USD) if applicable"
isLoading={ isPlaceholderData }
>
<CurrencyValue
value={ data.value }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
isLoading={ isPlaceholderData }
/>
</DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Burnt fees" title="Transaction fee"
hint={ `Amount of ${ appConfig.network.currency.symbol } burned for this transaction. Equals Block Base Fee per Gas * Gas Used` } hint="Total transaction fee"
isLoading={ isPlaceholderData }
> >
<Icon as={ flameIcon } mr={ 1 } boxSize={ 5 } color="gray.500"/>
<CurrencyValue <CurrencyValue
value={ String(data.tx_burnt_fee) } value={ data.fee.value }
currency={ appConfig.network.currency.symbol } currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate } exchangeRate={ data.exchange_rate }
flexWrap="wrap" flexWrap="wrap"
isLoading={ isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem>
) } <DetailsInfoItem
{ appConfig.L2.isL2Network && ( title="Gas price"
<> hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage"
{ data.l1_gas_used && ( isLoading={ isPlaceholderData }
<DetailsInfoItem >
title="L1 gas used by txn" <Skeleton isLoaded={ !isPlaceholderData } mr={ 1 }>
hint="L1 gas used by transaction" { BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }
isLoading={ isPlaceholderData } </Skeleton>
> <Skeleton isLoaded={ !isPlaceholderData } color="text_secondary">
<Text>{ BigNumber(data.l1_gas_used).toFormat() }</Text> <span>({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</span>
</DetailsInfoItem>
) }
{ data.l1_gas_price && (
<DetailsInfoItem
title="L1 gas price"
hint="L1 gas price"
isLoading={ isPlaceholderData }
>
<Text mr={ 1 }>{ BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text>
<Text variant="secondary">({ BigNumber(data.l1_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</Text>
</DetailsInfoItem>
) }
{ data.l1_fee && (
<DetailsInfoItem
title="L1 fee"
// eslint-disable-next-line max-len
hint={ `L1 Data Fee which is used to cover the L1 "security" cost from the batch submission mechanism. In combination with L2 execution fee, L1 fee makes the total amount of fees that a transaction pays.` }
isLoading={ isPlaceholderData }
>
<CurrencyValue
value={ data.l1_fee }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
/>
</DetailsInfoItem>
) }
{ data.l1_fee_scalar && (
<DetailsInfoItem
title="L1 fee scalar"
hint="A Dynamic overhead (fee scalar) premium, which serves as a buffer in case L1 prices rapidly increase."
isLoading={ isPlaceholderData }
>
<Text>{ data.l1_fee_scalar }</Text>
</DetailsInfoItem>
) }
</>
) }
<GridItem colSpan={{ base: undefined, lg: 2 }}>
<Element name="TxDetails__cutLink">
<Skeleton isLoaded={ !isPlaceholderData } mt={ 6 } display="inline-block">
<Link
display="inline-block"
fontSize="sm"
textDecorationLine="underline"
textDecorationStyle="dashed"
onClick={ handleCutClick }
>
{ isExpanded ? 'Hide details' : 'View details' }
</Link>
</Skeleton> </Skeleton>
</Element> </DetailsInfoItem>
</GridItem> <DetailsInfoItem
{ isExpanded && ( title="Gas usage & limit by txn"
<> hint="Actual gas amount used by the transaction"
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/> isLoading={ isPlaceholderData }
>
<Skeleton isLoaded={ !isPlaceholderData }>{ BigNumber(data.gas_used || 0).toFormat() }</Skeleton>
<TextSeparator/>
<Skeleton isLoaded={ !isPlaceholderData }>{ BigNumber(data.gas_limit).toFormat() }</Skeleton>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() } isLoading={ isPlaceholderData }/>
</DetailsInfoItem>
{ (data.base_fee_per_gas || data.max_fee_per_gas || data.max_priority_fee_per_gas) && (
<DetailsInfoItem <DetailsInfoItem
title="Other" title="Gas fees (Gwei)"
hint="Other data related to this transaction" // eslint-disable-next-line max-len
hint="Base Fee refers to the network Base Fee at the time of the block, while Max Fee & Max Priority Fee refer to the max amount a user is willing to pay for their tx & to give to the miner respectively"
isLoading={ isPlaceholderData }
> >
{ { data.base_fee_per_gas && (
[ <Skeleton isLoaded={ !isPlaceholderData }>
typeof data.type === 'number' && ( <Text as="span" fontWeight="500">Base: </Text>
<Box key="type"> <Text fontWeight="600" as="span">{ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
<Text as="span" fontWeight="500">Txn type: </Text> { (data.max_fee_per_gas || data.max_priority_fee_per_gas) && <TextSeparator/> }
<Text fontWeight="600" as="span">{ data.type }</Text> </Skeleton>
{ data.type === 2 && <Text fontWeight="400" as="span" ml={ 1 } variant="secondary">(EIP-1559)</Text> } ) }
</Box> { data.max_fee_per_gas && (
), <Box>
<Box key="nonce"> <Text as="span" fontWeight="500">Max: </Text>
<Text as="span" fontWeight="500">Nonce: </Text> <Text fontWeight="600" as="span">{ BigNumber(data.max_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
<Text fontWeight="600" as="span">{ data.nonce }</Text> { data.max_priority_fee_per_gas && <TextSeparator/> }
</Box>, </Box>
data.position !== null && ( ) }
<Box key="position"> { data.max_priority_fee_per_gas && (
<Text as="span" fontWeight="500">Position: </Text> <Box>
<Text fontWeight="600" as="span">{ data.position }</Text> <Text as="span" fontWeight="500">Max priority: </Text>
</Box> <Text fontWeight="600" as="span">{ BigNumber(data.max_priority_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() }</Text>
), </Box>
] ) }
.filter(Boolean)
.map((item, index) => (
<>
{ index !== 0 && <TextSeparator/> }
{ item }
</>
))
}
</DetailsInfoItem> </DetailsInfoItem>
) }
{ data.tx_burnt_fee && !appConfig.L2.isL2Network && (
<DetailsInfoItem <DetailsInfoItem
title="Raw input" title="Burnt fees"
hint="Binary data included with the transaction. See logs tab for additional info" hint={ `Amount of ${ appConfig.network.currency.symbol } burned for this transaction. Equals Block Base Fee per Gas * Gas Used` }
> >
<RawInputData hex={ data.raw_input }/> <Icon as={ flameIcon } mr={ 1 } boxSize={ 5 } color="gray.500"/>
<CurrencyValue
value={ String(data.tx_burnt_fee) }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
/>
</DetailsInfoItem> </DetailsInfoItem>
{ data.decoded_input && ( ) }
{ appConfig.L2.isL2Network && (
<>
{ data.l1_gas_used && (
<DetailsInfoItem
title="L1 gas used by txn"
hint="L1 gas used by transaction"
isLoading={ isPlaceholderData }
>
<Text>{ BigNumber(data.l1_gas_used).toFormat() }</Text>
</DetailsInfoItem>
) }
{ data.l1_gas_price && (
<DetailsInfoItem
title="L1 gas price"
hint="L1 gas price"
isLoading={ isPlaceholderData }
>
<Text mr={ 1 }>{ BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol }</Text>
<Text variant="secondary">({ BigNumber(data.l1_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei)</Text>
</DetailsInfoItem>
) }
{ data.l1_fee && (
<DetailsInfoItem
title="L1 fee"
// eslint-disable-next-line max-len
hint={ `L1 Data Fee which is used to cover the L1 "security" cost from the batch submission mechanism. In combination with L2 execution fee, L1 fee makes the total amount of fees that a transaction pays.` }
isLoading={ isPlaceholderData }
>
<CurrencyValue
value={ data.l1_fee }
currency={ appConfig.network.currency.symbol }
exchangeRate={ data.exchange_rate }
flexWrap="wrap"
/>
</DetailsInfoItem>
) }
{ data.l1_fee_scalar && (
<DetailsInfoItem
title="L1 fee scalar"
hint="A Dynamic overhead (fee scalar) premium, which serves as a buffer in case L1 prices rapidly increase."
isLoading={ isPlaceholderData }
>
<Text>{ data.l1_fee_scalar }</Text>
</DetailsInfoItem>
) }
</>
) }
<GridItem colSpan={{ base: undefined, lg: 2 }}>
<Element name="TxDetails__cutLink">
<Skeleton isLoaded={ !isPlaceholderData } mt={ 6 } display="inline-block">
<Link
display="inline-block"
fontSize="sm"
textDecorationLine="underline"
textDecorationStyle="dashed"
onClick={ handleCutClick }
>
{ isExpanded ? 'Hide details' : 'View details' }
</Link>
</Skeleton>
</Element>
</GridItem>
{ isExpanded && (
<>
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
<DetailsInfoItem <DetailsInfoItem
title="Decoded input data" title="Other"
hint="Decoded input data" hint="Other data related to this transaction"
> >
<LogDecodedInputData data={ data.decoded_input }/> {
[
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> }
</Box>
),
<Box key="nonce">
<Text as="span" fontWeight="500">Nonce: </Text>
<Text fontWeight="600" as="span">{ data.nonce }</Text>
</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>
) } <DetailsInfoItem
</> title="Raw input"
) } hint="Binary data included with the transaction. See logs tab for additional info"
</Grid> >
<RawInputData hex={ data.raw_input }/>
</DetailsInfoItem>
{ data.decoded_input && (
<DetailsInfoItem
title="Decoded input data"
hint="Decoded input data"
>
<LogDecodedInputData data={ data.decoded_input }/>
</DetailsInfoItem>
) }
</>
) }
</Grid>
</>
); );
}; };
......
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