customize fees section on tx page and add new option for network validation type

This commit is contained in:
tom
2025-10-14 12:16:26 +02:00
parent b6dd2801de
commit d15c16ecfe
46 changed files with 298 additions and 51 deletions
+1
View File
@@ -36,6 +36,7 @@ const additionalFields = (() => {
const config = Object.freeze({
hiddenFields,
additionalFields,
groupedFees: getEnvValue('NEXT_PUBLIC_VIEWS_TX_GROUPED_FEES') === 'true',
});
export default config;
+2 -1
View File
@@ -787,7 +787,7 @@ const schema = yup
NEXT_PUBLIC_NETWORK_SECONDARY_COIN_SYMBOL: yup.string(),
NEXT_PUBLIC_NETWORK_MULTIPLE_GAS_CURRENCIES: yup.boolean(),
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE: yup
.string<NetworkVerificationTypeEnvs>().oneOf([ 'validation', 'mining' ])
.string<NetworkVerificationTypeEnvs>().oneOf([ 'validation', 'mining', 'fee reception' ])
.when('NEXT_PUBLIC_ROLLUP_TYPE', {
is: (value: string) => value === 'arbitrum' || value === 'zkEvm',
then: (schema) => schema.test(
@@ -982,6 +982,7 @@ const schema = yup
.transform(replaceQuotes)
.json()
.of(yup.string<TxAdditionalFieldsId>().oneOf(TX_ADDITIONAL_FIELDS_IDS)),
NEXT_PUBLIC_VIEWS_TX_GROUPED_FEES: yup.boolean(),
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES: yup
.array()
.transform(replaceQuotes)
+1 -1
View File
@@ -73,7 +73,7 @@ NEXT_PUBLIC_VIEWS_CONTRACT_LANGUAGE_FILTERS=['solidity','vyper','yul','scilla','
NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees','total_reward']
NEXT_PUBLIC_VIEWS_BLOCK_PENDING_UPDATE_ALERT_ENABLED=false
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'NFT Marketplace','collection_url':'https://example.com/{hash}','instance_url':'https://example.com/{hash}/{id}','logo_url':'https://example.com/logo.png'}]
NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS=['fee_per_gas']
NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS=['fee_per_gas','set_max_gas_limit']
NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS=['value','fee_currency','gas_price','tx_fee','gas_fees','burnt_fees']
NEXT_PUBLIC_VISUALIZE_API_HOST=https://example.com
NEXT_PUBLIC_VISUALIZE_API_BASE_PATH=https://example.com
+3 -1
View File
@@ -113,7 +113,7 @@ All json-like values should be single-quoted. If it contains a hash (`#`) or a d
| NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS | `string` | Network currency decimals | - | `18` | `6` | v1.0.x+ |
| NEXT_PUBLIC_NETWORK_SECONDARY_COIN_SYMBOL | `string` | Network secondary coin symbol. | - | - | `GNO` | v1.29.0+ |
| NEXT_PUBLIC_NETWORK_MULTIPLE_GAS_CURRENCIES | `boolean` | Set to `true` for networks where users can pay transaction fees in either the native coin or ERC-20 tokens. | - | `false` | `true` | v1.33.0+ |
| NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE | `validation` \| `mining` | Verification type in the network. Irrelevant for Arbitrum (verification type is always `posting`) and ZkEvm (verification type is always `sequencing`) L2s | - | `mining` | `validation` | v1.0.x+ |
| NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE | `validation` \| `mining` \| 'fee reception' | Verification type in the network. Irrelevant for Arbitrum (verification type is always `posting`) and ZkEvm (verification type is always `sequencing`) L2s | - | `mining` | `validation` | v1.0.x+ |
| NEXT_PUBLIC_NETWORK_TOKEN_STANDARD_NAME | `string` | Name of the standard for creating tokens | - | `ERC` | `BEP` | v1.31.0+ |
| NEXT_PUBLIC_IS_TESTNET | `boolean`| Set to true if network is testnet | - | `false` | `true` | v1.0.x+ |
@@ -297,6 +297,7 @@ Settings for meta tags, OG tags and SEO
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS | `Array<TxFieldsId>` | Array of the transaction fields ids that should be hidden. See below the list of the possible id values. | - | - | `'["value","tx_fee"]'` | v1.15.0+ |
| NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS | `Array<TxAdditionalFieldsId>` | Array of the additional fields ids that should be added to the transaction details. See below the list of the possible id values. | - | - | `'["fee_per_gas"]'` | v1.15.0+ |
| NEXT_PUBLIC_VIEWS_TX_GROUPED_FEES | `boolean` | In the detailed view group transaction fees under one collapsible section. | - | - | `true` | v2.3.5+ |
##### Transaction fields list
| Id | Description |
@@ -314,6 +315,7 @@ Settings for meta tags, OG tags and SEO
| Id | Description |
| --- | --- |
| `fee_per_gas` | Amount of total fee divided by total amount of gas used by transaction |
| `set_max_gas_limit` | Max gas price established by the sender |
&nbsp;
+1 -1
View File
@@ -28,5 +28,5 @@ export default function getCurrencyValue({ value, accuracy, accuracyUsd, decimal
}
}
return { valueStr: valueResult, usd: usdResult, usdBn };
return { valueCurr, valueStr: valueResult, usd: usdResult, usdBn };
}
@@ -14,8 +14,11 @@ export default function getNetworkValidationActionText(chainConfig = config) {
case 'sequencing': {
return 'sequenced';
}
case 'fee reception': {
return 'validated';
}
default: {
return 'miner';
return 'mined';
}
}
}
+3
View File
@@ -14,6 +14,9 @@ export default function getNetworkValidatorTitle() {
case 'sequencing': {
return 'sequencer';
}
case 'fee reception': {
return 'fee recipient';
}
default: {
return 'miner';
}
+1 -1
View File
@@ -6,7 +6,7 @@ import { useUpdateEffect } from '../hooks/useUpdateEffect';
import type { LinkProps } from './link';
import { Link } from './link';
interface CollapsibleDetailsProps extends LinkProps {
export interface CollapsibleDetailsProps extends LinkProps {
children: React.ReactNode;
id?: string;
isExpanded?: boolean;
+1 -1
View File
@@ -25,6 +25,6 @@ export interface NetworkExplorer {
};
}
export type NetworkVerificationTypeEnvs = 'mining' | 'validation';
export type NetworkVerificationTypeEnvs = 'mining' | 'validation' | 'fee reception';
export type NetworkVerificationTypeComputed = 'posting' | 'sequencing';
export type NetworkVerificationType = NetworkVerificationTypeEnvs | NetworkVerificationTypeComputed;
+1
View File
@@ -15,6 +15,7 @@ export type TxFieldsId = ArrayElement<typeof TX_FIELDS_IDS>;
export const TX_ADDITIONAL_FIELDS_IDS = [
'fee_per_gas',
'set_max_gas_limit',
] as const;
export type TxAdditionalFieldsId = ArrayElement<typeof TX_ADDITIONAL_FIELDS_IDS>;
+1 -4
View File
@@ -11,7 +11,6 @@ import { route, routeParams } from 'nextjs/routes';
import config from 'configs/app';
import getBlockReward from 'lib/block/getBlockReward';
import { useMultichainContext } from 'lib/contexts/multichain';
import getNetworkValidationActionText from 'lib/networks/getNetworkValidationActionText';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import * as arbitrum from 'lib/rollups/arbitrum';
import getQueryParamString from 'lib/router/getQueryParamString';
@@ -111,8 +110,6 @@ const BlockDetails = ({ query }: Props) => {
);
})();
const verificationTitle = `${ capitalize(getNetworkValidationActionText()) } by`;
const txsNum = (() => {
const blockTxsNum = (
<Link href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: heightOrHash, tab: 'txs' } }, multichainContext) }>
@@ -326,7 +323,7 @@ const BlockDetails = ({ query }: Props) => {
hint="A block producer who successfully included the block onto the blockchain"
isLoading={ isPlaceholderData }
>
{ verificationTitle }
{ capitalize(validatorTitle) }
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<AddressEntity
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 107 KiB

+2 -1
View File
@@ -1,4 +1,5 @@
import { Box, Flex, Grid } from '@chakra-ui/react';
import { capitalize } from 'es-toolkit';
import React from 'react';
import type { Block } from 'types/api/block';
@@ -73,7 +74,7 @@ const LatestBlocksItem = ({ block, isLoading, animation }: Props) => {
{ !config.features.rollup.isEnabled && !config.UI.views.block.hiddenFields?.miner && (
<>
<Skeleton loading={ isLoading } textTransform="capitalize">{ getNetworkValidatorTitle() }</Skeleton>
<Skeleton loading={ isLoading }>{ capitalize(getNetworkValidatorTitle()) }</Skeleton>
<AddressEntity
address={ block.miner }
isLoading={ isLoading }
+2 -2
View File
@@ -13,7 +13,7 @@ import { useMultichainContext } from 'lib/contexts/multichain';
import throwOnAbsentParamError from 'lib/errors/throwOnAbsentParamError';
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import useIsMobile from 'lib/hooks/useIsMobile';
import getNetworkValidationActionText from 'lib/networks/getNetworkValidationActionText';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import getQueryParamString from 'lib/router/getQueryParamString';
import { Skeleton } from 'toolkit/chakra/skeleton';
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
@@ -186,7 +186,7 @@ const BlockPageContent = () => {
fontWeight={ 500 }
>
<chakra.span flexShrink={ 0 }>
{ `${ capitalize(getNetworkValidationActionText()) } by` }
{ capitalize(getNetworkValidatorTitle()) }
</chakra.span>
<AddressEntity address={ blockQuery.data.miner }/>
</Skeleton>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

+18 -5
View File
@@ -2,7 +2,10 @@ import { chakra } from '@chakra-ui/react';
import React from 'react';
import getCurrencyValue from 'lib/getCurrencyValue';
import { currencyUnits } from 'lib/units';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Tooltip } from 'toolkit/chakra/tooltip';
import { GWEI } from 'toolkit/utils/consts';
interface Props {
value: string | null;
@@ -14,9 +17,10 @@ interface Props {
decimals?: string | null;
isLoading?: boolean;
startElement?: React.ReactNode;
showGweiTooltip?: boolean;
}
const CurrencyValue = ({ value, currency = '', decimals, exchangeRate, className, accuracy, accuracyUsd, isLoading, startElement }: Props) => {
const CurrencyValue = ({ value, currency = '', decimals, exchangeRate, className, accuracy, accuracyUsd, isLoading, startElement, showGweiTooltip }: Props) => {
if (isLoading) {
return (
<Skeleton className={ className } loading display="inline-block">0.00 ($0.00)</Skeleton>
@@ -30,14 +34,23 @@ const CurrencyValue = ({ value, currency = '', decimals, exchangeRate, className
</chakra.span>
);
}
const { valueStr: valueResult, usd: usdResult } = getCurrencyValue({ value, accuracy, accuracyUsd, exchangeRate, decimals });
const { valueCurr, valueStr: valueResult, usd: usdResult } = getCurrencyValue({ value, accuracy, accuracyUsd, exchangeRate, decimals });
const valueElement = (
<chakra.span display="inline-block">
{ valueResult }{ currency ? ` ${ currency }` : '' }
</chakra.span>
);
const valueInGwei = showGweiTooltip ? valueCurr.multipliedBy(GWEI).toFormat() : null;
return (
<chakra.span className={ className } display="inline-flex" rowGap={ 3 } columnGap={ 1 }>
{ startElement }
<chakra.span display="inline-block">
{ valueResult }{ currency ? ` ${ currency }` : '' }
</chakra.span>
{ showGweiTooltip ? (
<Tooltip content={ `${ valueInGwei } ${ currencyUnits.gwei }` }>
{ valueElement }
</Tooltip>
) : valueElement }
{ usdResult && <chakra.span color="text.secondary" fontWeight={ 400 }>(${ usdResult })</chakra.span> }
</chakra.span>
);
@@ -0,0 +1,49 @@
import { Grid, GridItem } from '@chakra-ui/react';
import React from 'react';
import type { CollapsibleDetailsProps } from 'toolkit/chakra/collapsible';
import { CollapsibleDetails } from 'toolkit/chakra/collapsible';
import { Hint } from 'toolkit/components/Hint/Hint';
import TruncatedValue from 'ui/shared/TruncatedValue';
interface ContainerProps extends CollapsibleDetailsProps {}
export const Container = ({ children, ...rest }: ContainerProps) => {
return (
<CollapsibleDetails noScroll variant="secondary" display="block" textStyle={ undefined } fontSize="sm" { ...rest }>
<Grid
gridTemplateColumns="max-content minmax(0px, 1fr)"
alignItems="start"
textStyle="sm"
bgColor={{ _light: 'blackAlpha.50', _dark: 'whiteAlpha.50' }}
w="100%"
p={{ base: 2, lg: 3 }}
mt={ 1 }
columnGap={ 3 }
rowGap={ 4 }
borderBottomRightRadius="base"
borderBottomLeftRadius="base"
>
{ children }
</Grid>
</CollapsibleDetails>
);
};
interface RowProps {
label: string;
hint: string;
children: React.ReactNode;
}
export const Row = ({ label, hint, children }: RowProps) => {
return (
<>
<GridItem color="text.secondary" display="flex" alignItems="center">
<Hint label={ hint } boxSize={ 4 } mr={ 1 }/>
<TruncatedValue value={ label } maxW={{ base: '130px', lg: 'unset' }}/>
</GridItem>
{ children }
</>
);
};
+35
View File
@@ -0,0 +1,35 @@
import BigNumber from 'bignumber.js';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import { Skeleton } from 'toolkit/chakra/skeleton';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import TextSeparator from 'ui/shared/TextSeparator';
import Utilization from 'ui/shared/Utilization/Utilization';
interface Props {
isLoading?: boolean;
data: Transaction;
}
const TxDetailsGasUsage = ({ isLoading, data }: Props) => {
return (
<>
<DetailedInfo.ItemLabel
hint="Actual gas amount used by the transaction"
isLoading={ isLoading }
>
Gas usage & limit by txn
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton loading={ isLoading }>{ BigNumber(data.gas_used || 0).toFormat() }</Skeleton>
<TextSeparator/>
<Skeleton loading={ isLoading }>{ BigNumber(data.gas_limit).toFormat() }</Skeleton>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() } isLoading={ isLoading }/>
</DetailedInfo.ItemValue>
</>
);
};
export default React.memo(TxDetailsGasUsage);
+47
View File
@@ -0,0 +1,47 @@
import BigNumber from 'bignumber.js';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import config from 'configs/app';
import { currencyUnits } from 'lib/units';
import CurrencyValue from 'ui/shared/CurrencyValue';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import TxDetailsGasUsage from './TxDetailsGasUsage';
interface Props {
data: Transaction;
}
const TxDetailsSetMaxGasLimit = ({ data }: Props) => {
if (!config.UI.views.tx.additionalFields?.set_max_gas_limit) {
return null;
}
const maxGasLimit = BigNumber(data.gas_limit || 0).multipliedBy(BigNumber(data.gas_price || 0));
return (
<>
<DetailedInfo.ItemLabel
hint="The maximum network fee the sender is willing to pay for this transaction"
>
User’s set max gas limit
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue multiRow>
<CurrencyValue
value={ maxGasLimit.toString() }
currency={ currencyUnits.ether }
exchangeRate={ 'exchange_rate' in data ? data.exchange_rate : null }
showGweiTooltip
flexWrap="wrap"
mr={ 3 }
rowGap={ 0 }
/>
</DetailedInfo.ItemValue>
<TxDetailsGasUsage data={ data }/>
</>
);
};
export default React.memo(TxDetailsSetMaxGasLimit);
+101
View File
@@ -0,0 +1,101 @@
import BigNumber from 'bignumber.js';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import config from 'configs/app';
import { currencyUnits } from 'lib/units';
import CurrencyValue from 'ui/shared/CurrencyValue';
import * as DetailedInfo from 'ui/shared/DetailedInfo/DetailedInfo';
import * as DetailedInfoItemBreakdown from 'ui/shared/DetailedInfo/DetailedInfoItemBreakdown';
import TxFee from 'ui/shared/tx/TxFee';
interface Props {
isLoading: boolean;
data: Transaction;
}
const TxDetailsTxFee = ({ isLoading, data }: Props) => {
if (config.UI.views.tx.hiddenFields?.tx_fee) {
return null;
}
const content = (() => {
if (!config.UI.views.tx.groupedFees) {
return (
<TxFee
tx={ data }
isLoading={ isLoading }
withUsd
rowGap={ 0 }
/>
);
}
const baseFeeBn = BigNumber(data.base_fee_per_gas || 0).multipliedBy(data.gas_used || 0);
const priorityFeeBn = BigNumber(data.priority_fee || 0);
return (
<>
<CurrencyValue
value={ data.fee.value }
currency={ currencyUnits.ether }
exchangeRate={ 'exchange_rate' in data ? data.exchange_rate : null }
isLoading={ isLoading }
showGweiTooltip
flexWrap="wrap"
mr={ 3 }
rowGap={ 0 }
/>
<DetailedInfoItemBreakdown.Container loading={ isLoading }>
<DetailedInfoItemBreakdown.Row
label="Base fee"
hint="The minimum network fee charged per transaction"
>
<CurrencyValue
value={ baseFeeBn.toString() }
currency={ currencyUnits.ether }
exchangeRate={ 'exchange_rate' in data ? data.exchange_rate : null }
isLoading={ isLoading }
showGweiTooltip
flexWrap="wrap"
rowGap={ 0 }
/>
</DetailedInfoItemBreakdown.Row>
<DetailedInfoItemBreakdown.Row
label="Priority fee"
hint="An extra fee set by the sender to speed up transaction execution"
>
<CurrencyValue
value={ priorityFeeBn.toString() }
currency={ currencyUnits.ether }
exchangeRate={ 'exchange_rate' in data ? data.exchange_rate : null }
isLoading={ isLoading }
showGweiTooltip
flexWrap="wrap"
rowGap={ 0 }
/>
</DetailedInfoItemBreakdown.Row>
</DetailedInfoItemBreakdown.Container>
</>
);
})();
return (
<>
<DetailedInfo.ItemLabel
hint={ data.blob_gas_used ? 'Transaction fee without blob fee' : 'Total transaction fee' }
isLoading={ isLoading }
>
Transaction fee
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue multiRow>
{ content }
</DetailedInfo.ItemValue>
</>
);
};
export default React.memo(TxDetailsTxFee);
+17
View File
@@ -121,6 +121,23 @@ test('stability customization', async({ render, page, mockEnvs, mockAssetRespons
});
});
test('with grouped fees', async({ render, page, mockEnvs }) => {
await mockEnvs([
[ 'NEXT_PUBLIC_VIEWS_TX_GROUPED_FEES', 'true' ],
[ 'NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS', '["gas_price","gas_fees","burnt_fees"]' ],
[ 'NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS', '["set_max_gas_limit"]' ],
]);
const component = await render(<TxInfo data={ txMock.base } isLoading={ false }/>);
await component.getByText('View details').first().click();
await component.getByText('View details').first().click();
await expect(component).toHaveScreenshot({
mask: [ page.locator(pwConfig.adsBannerSelector) ],
maskColor: pwConfig.maskColor,
});
});
test('arbitrum L1 status', async({ render, mockEnvs }) => {
await mockEnvs(ENVS_MAP.arbitrumRollup);
const component = await render(<TxInfo data={ txMock.arbitrumTxn } isLoading={ false }/>);
+8 -32
View File
@@ -48,7 +48,6 @@ import RawInputData from 'ui/shared/RawInputData';
import StatusTag from 'ui/shared/statusTag/StatusTag';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import TextSeparator from 'ui/shared/TextSeparator';
import TxFee from 'ui/shared/tx/TxFee';
import Utilization from 'ui/shared/Utilization/Utilization';
import VerificationSteps from 'ui/shared/verificationSteps/VerificationSteps';
import TxDetailsActions from 'ui/tx/details/txDetailsActions/TxDetailsActions';
@@ -64,8 +63,11 @@ import TxExternalTxs from 'ui/tx/TxExternalTxs';
import TxSocketAlert from 'ui/tx/TxSocketAlert';
import ZkSyncL2TxnBatchHashesInfo from 'ui/txnBatches/zkSyncL2/ZkSyncL2TxnBatchHashesInfo';
import TxDetailsGasUsage from './TxDetailsGasUsage';
import TxDetailsInterop from './TxDetailsInterop';
import TxDetailsSetMaxGasLimit from './TxDetailsSetMaxGasLimit';
import TxDetailsTacOperation from './TxDetailsTacOperation';
import TxDetailsTxFee from './TxDetailsTxFee';
import TxDetailsWithdrawalStatusArbitrum from './TxDetailsWithdrawalStatusArbitrum';
import TxInfoScrollFees from './TxInfoScrollFees';
@@ -137,7 +139,7 @@ const TxInfo = ({ data, tacOperations, isLoading, socketStatus }: Props) => {
const hasInterop = rollupFeature.isEnabled && rollupFeature.interopEnabled && data.op_interop_messages && data.op_interop_messages.length > 0;
return (
<DetailedInfo.Container>
<DetailedInfo.Container templateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(215px, auto) minmax(0, 1fr)' }}>
{ config.features.metasuites.isEnabled && (
<>
@@ -623,24 +625,7 @@ const TxInfo = ({ data, tacOperations, isLoading, socketStatus }: Props) => {
</>
) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && (
<>
<DetailedInfo.ItemLabel
hint={ data.blob_gas_used ? 'Transaction fee without blob fee' : 'Total transaction fee' }
isLoading={ isLoading }
>
Transaction fee
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue multiRow>
<TxFee
tx={ data }
isLoading={ isLoading }
withUsd
rowGap={ 0 }
/>
</DetailedInfo.ItemValue>
</>
) }
<TxDetailsTxFee isLoading={ isLoading } data={ data }/>
{ rollupFeature.isEnabled && rollupFeature.type === 'arbitrum' && data.arbitrum && (
<>
@@ -682,18 +667,7 @@ const TxInfo = ({ data, tacOperations, isLoading, socketStatus }: Props) => {
<TxDetailsFeePerGas txFee={ data.fee.value } gasUsed={ data.gas_used } isLoading={ isLoading }/>
<DetailedInfo.ItemLabel
hint="Actual gas amount used by the transaction"
isLoading={ isLoading }
>
Gas usage & limit by txn
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue>
<Skeleton loading={ isLoading }>{ BigNumber(data.gas_used || 0).toFormat() }</Skeleton>
<TextSeparator/>
<Skeleton loading={ isLoading }>{ BigNumber(data.gas_limit).toFormat() }</Skeleton>
<Utilization ml={ 4 } value={ BigNumber(data.gas_used || 0).dividedBy(BigNumber(data.gas_limit)).toNumber() } isLoading={ isLoading }/>
</DetailedInfo.ItemValue>
{ !config.UI.views.tx.additionalFields?.set_max_gas_limit && <TxDetailsGasUsage isLoading={ isLoading } data={ data }/> }
{ rollupFeature.isEnabled && rollupFeature.type === 'arbitrum' && data.arbitrum && data.gas_used && (
<>
@@ -859,6 +833,8 @@ const TxInfo = ({ data, tacOperations, isLoading, socketStatus }: Props) => {
<CollapsibleDetails loading={ isLoading } mt={ 6 } gridColumn={{ base: undefined, lg: '1 / 3' }} isExpanded={ isExpanded } onClick={ handleCutLinkClick }>
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
<TxDetailsSetMaxGasLimit data={ data }/>
<TxDetailsWithdrawalStatusArbitrum data={ data }/>
{ (data.blob_gas_used || data.max_fee_per_blob_gas || data.blob_gas_price) && (
Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB