Skip to content
This repository was archived by the owner on Jan 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/block/getBlockReward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { Block } from 'types/api/block';

export default function getBlockReward(block: Block) {
const txFees = BigNumber(block.transaction_fees || 0);
const priorityFee = BigNumber(block.priority_fee || 0);
const burntFees = BigNumber(block.burnt_fees || 0);
const minerReward = block.rewards?.find(({ type }) => type === 'Miner Reward' || type === 'Validator Reward')?.reward;
const totalReward = BigNumber(minerReward || 0);
Expand All @@ -14,5 +15,6 @@ export default function getBlockReward(block: Block) {
staticReward,
txFees,
burntFees,
priorityFee,
};
}
26 changes: 21 additions & 5 deletions ui/block/BlockDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,17 @@ const BlockDetails = ({ query }: Props) => {

const validatorTitle = getNetworkValidatorTitle();

const shouldHideRewardBreakdown = () => {
return (
rollupFeature.isEnabled ||
totalReward.isEqualTo(ZERO) ||
txFees.isEqualTo(ZERO) ||
burntFees.isEqualTo(ZERO)
) && data.withdrawals_count === 0;
};

const rewardBreakDown = (() => {
if (rollupFeature.isEnabled || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) {
if (shouldHideRewardBreakdown()) {
return null;
}

Expand Down Expand Up @@ -345,19 +354,26 @@ const BlockDetails = ({ query }: Props) => {
</>
) }

{ !rollupFeature.isEnabled && !totalReward.isEqualTo(ZERO) && (
{ !rollupFeature.isEnabled && (data.withdrawals_count ?? 0) > 0 && (
<>
<DetailedInfo.ItemLabel
hint={
`For each block, the ${ validatorTitle } is rewarded with a finite amount of ${ config.chain.currency.symbol || 'native token' }
on top of the fees paid for all transactions in the block`
data.transactions_count > 0 && data.burnt_fees !== '0' ?
`For each block, the ${ validatorTitle } is rewarded with a finite amount of ${ config.chain.currency.symbol || 'native token' }
on top of the fees paid for all transactions in the block` :
'Mining rewards'
}
isLoading={ isPlaceholderData }
>
Block reward
</DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue columnGap={ 1 }>
<Skeleton loading={ isPlaceholderData } minH="140px" minW={{ base: '100%', md: '400px' }} w={{ base: '100%', md: 'min-content' }}>
<Skeleton
loading={ isPlaceholderData }
minH={ data.transactions_count > 0 && data.burnt_fees !== '0' ? '140px' : '24px' }
minW={{ base: '100%', md: '400px' }}
w={{ base: '100%', md: 'min-content' }}
>
{ rewardBreakDown }
</Skeleton>
</DetailedInfo.ItemValue>
Expand Down
214 changes: 111 additions & 103 deletions ui/block/BlockRewards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ const KDABlockRewards = ({ query }: Props) => {
const handleBurntFeesValuesMouseLeave = useCallback(() => onMouseLeaveValues(burntFeesValuesRef), [ onMouseLeaveValues ]);

if (isLoading) {
return <Skeleton loading={ isLoading } minH="140px" maxW="380px" w="100%"/>;
return <Skeleton loading={ isLoading } minH={ hasTxFees && hasBurntFees ? '140px' : '24px' } maxW="380px" w="100%"/>;
}

if (!calculatedValues) {
Expand All @@ -170,110 +170,118 @@ const KDABlockRewards = ({ query }: Props) => {
<chakra.span fontFamily="var(--kda-typography-family-monospace-font)">
{ rewardAmount } { currencyUnits.ether }
</chakra.span>
<chakra.div>
<Text color="text.primary" fontWeight="bold" fontSize="sm" display="inline">
Breakdown{ space }
</Text>
<chakra.div display={{ base: 'none', md: 'flex' }} flexDirection="row" gap={ 2 } alignItems="center" mt={ 3 }>
<KDABreakdownItem
ref={ blockRewardValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleBlockRewardMouseEnter }
onMouseLeave={ handleBlockRewardMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="PoW mining reward"/>
Mining reward
</chakra.span>
</Text>
</KDABreakdownItem>
+
<KDABreakdownItem
ref={ txFeesValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleTxFeesMouseEnter }
onMouseLeave={ handleTxFeesMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="Total transaction fees collected from all transactions in the block"/>
Transaction fees
</chakra.span>
</Text>
</KDABreakdownItem>
-
<KDABreakdownItem
ref={ burntFeesValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleBurntFeesMouseEnter }
onMouseLeave={ handleBurntFeesMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="Base fees burned (EIP-1559 mechanism)"/>
Burnt fees
</chakra.span>
</Text>
</KDABreakdownItem>
</chakra.div>
<RawDataSnippet
data={ (
<Text
display="flex"
flexDirection={{ base: 'column', md: 'row' }}
color="text.secondary"
fontSize="sm"
whiteSpace="nowrap"
gap={ 1 }
fontFamily="var(--kda-typography-family-monospace-font)">
{ hasRewardBaseFee && (
<Tooltip content="Block reward">
<BreakdownLabel
ref={ blockRewardLabelRef }
onMouseEnterValues={ handleBlockRewardValuesMouseEnter }
onMouseLeaveValues={ handleBlockRewardValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Reward fee:
</chakra.span>
<span>{ rewardBaseFee }</span>
</BreakdownLabel>
</Tooltip>
)
}
{ space }+{ space }
{ hasTxFees && (
<Tooltip content="Total transaction fees">
<BreakdownLabel
ref={ txFeesLabelRef }
onMouseEnterValues={ handleTxFeesValuesMouseEnter }
onMouseLeaveValues={ handleTxFeesValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Transaction fees:
</chakra.span>
<span>{ txFees }</span>
</BreakdownLabel>
</Tooltip>
) }
{ space }-{ space }
{ hasBurntFees && (
<Tooltip content="Burnt fees">
<BreakdownLabel
ref={ burntFeesLabelRef }
onMouseEnterValues={ handleBurntFeesValuesMouseEnter }
onMouseLeaveValues={ handleBurntFeesValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Burnt fees:{ ' ' }
</chakra.span>
<span>{ burntFees }</span>
</BreakdownLabel>
</Tooltip>
{ hasTxFees && hasBurntFees && (
<chakra.div>
<Text color="text.primary" fontWeight="bold" fontSize="sm" display="inline">
Breakdown{ space }
</Text>
<chakra.div display={{ base: 'none', md: 'flex' }} flexDirection="row" gap={ 2 } alignItems="center" mt={ 3 }>
<KDABreakdownItem
ref={ blockRewardValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleBlockRewardMouseEnter }
onMouseLeave={ handleBlockRewardMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="PoW mining reward"/>
Mining reward
</chakra.span>
</Text>
</KDABreakdownItem>
+
<KDABreakdownItem
ref={ txFeesValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleTxFeesMouseEnter }
onMouseLeave={ handleTxFeesMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="Total transaction fees collected from all transactions in the block"/>
Transaction fees
</chakra.span>
</Text>
</KDABreakdownItem>
-
<KDABreakdownItem
ref={ burntFeesValuesRef }
isLoading={ isLoading }
onMouseEnter={ handleBurntFeesMouseEnter }
onMouseLeave={ handleBurntFeesMouseLeave }>
<Text color="text.primary" fontSize="sm" display="inline" fontFamily="var(--global-font-body, var(--font-fallback))">
<chakra.span whiteSpace="nowrap">
<Hint label="Base fees burned (EIP-1559 mechanism)"/>
Burnt fees
</chakra.span>
</Text>
</KDABreakdownItem>
</chakra.div>
{ hasTxFees && hasBurntFees && (
<RawDataSnippet
data={ (
<Text
display="flex"
flexDirection={{ base: 'column', md: 'row' }}
color="text.secondary"
fontSize="sm"
whiteSpace="nowrap"
gap={ 1 }
fontFamily="var(--kda-typography-family-monospace-font)">
{ hasRewardBaseFee && (
<Tooltip content="Block reward">
<BreakdownLabel
ref={ blockRewardLabelRef }
onMouseEnterValues={ handleBlockRewardValuesMouseEnter }
onMouseLeaveValues={ handleBlockRewardValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Reward fee:
</chakra.span>
<span>{ rewardBaseFee }</span>
</BreakdownLabel>
</Tooltip>
)
}
{ hasTxFees && (
<>
{ space }+{ space }
<Tooltip content="Total transaction fees">
<BreakdownLabel
ref={ txFeesLabelRef }
onMouseEnterValues={ handleTxFeesValuesMouseEnter }
onMouseLeaveValues={ handleTxFeesValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Transaction fees:
</chakra.span>
<span>{ txFees }</span>
</BreakdownLabel>
</Tooltip>
</>
) }
{ hasBurntFees && (
<>
{ space }-{ space }
<Tooltip content="Burnt fees">
<BreakdownLabel
ref={ burntFeesLabelRef }
onMouseEnterValues={ handleBurntFeesValuesMouseEnter }
onMouseLeaveValues={ handleBurntFeesValuesMouseLeave }
>
<chakra.span display={{ base: '', md: 'none' }} fontFamily="var(--global-font-body, var(--font-fallback))">
Burnt fees:{ ' ' }
</chakra.span>
<span>{ burntFees }</span>
</BreakdownLabel>
</Tooltip>
</>
) }
</Text>
) }
</Text>
isLoading={ isLoading }
/>
) }
isLoading={ isLoading }
/>
</chakra.div>
</chakra.div>
) }
</chakra.div>
);
};
Expand Down
19 changes: 14 additions & 5 deletions ui/block/useKDABlockRewards.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import BigNumber from 'bignumber.js';
import { useRouter } from 'next/router';
import { useMemo } from 'react';

import useApiQuery from 'lib/api/useApiQuery';
import getBlockReward from 'lib/block/getBlockReward';
import getQueryParamString from 'lib/router/getQueryParamString';
import { WEI, ZERO } from 'toolkit/utils/consts';

import getBlockReward from '../../lib/block/getBlockReward';
import type { BlockQuery } from './useBlockQuery';

export type TKDABlockRewardsData = {
Expand All @@ -24,42 +26,48 @@ export type TKDABlockRewardsData = {
burntFees: BigNumber;
hasRewardBaseFee: boolean;
hasTxFees: boolean;
hasPriorityFee: boolean;
hasBurntFees: boolean;
} | null;
formattedValues: {
rewardAmount?: string;
rewardBaseFee?: string;
txFees?: string;
priorityFee?: string;
burntFees?: string;
};
};

export const useKDABlockRewardsData = (query: BlockQuery): TKDABlockRewardsData => {
const router = useRouter();
const { data, isLoading: queryIsLoading } = query;
const heightOrHash = getQueryParamString(router.query.height_or_hash ?? data?.height.toString() ?? data?.hash ?? '');
const { data: withdrawalsData, isLoading: withdrawalsIsLoading } = useApiQuery('general:block_withdrawals', {
queryParams: { height_or_hash: `${ data?.height }` },
queryParams: { height_or_hash: heightOrHash },
});
const { totalReward, burntFees, txFees } = data ? getBlockReward(data) : { totalReward: ZERO, burntFees: ZERO, txFees: ZERO };
const { totalReward, burntFees, txFees, priorityFee } = data ? getBlockReward(data) : { totalReward: ZERO, burntFees: ZERO, txFees: ZERO, priorityFee: ZERO };

const calculatedValues = useMemo(() => {
if (!withdrawalsData?.items?.length) {
return null;
}

const [ reward ] = withdrawalsData.items;
const rewardAmount = BigNumber(reward.amount ?? 0);
const rewardAmount = BigNumber((reward.amount ?? 0)).plus(priorityFee.toNumber());
const rewardBaseFee = BigNumber(rewardAmount.toNumber() - totalReward.toNumber() + burntFees.toNumber());

return {
rewardAmount: rewardAmount.dividedBy(WEI),
rewardBaseFee: rewardBaseFee.dividedBy(WEI),
txFees: txFees.dividedBy(WEI),
priorityFee: priorityFee.dividedBy(WEI),
burntFees: burntFees.dividedBy(WEI),
hasRewardBaseFee: !rewardBaseFee.isEqualTo(ZERO),
hasTxFees: !txFees.isEqualTo(ZERO),
hasPriorityFee: !priorityFee.isEqualTo(ZERO),
hasBurntFees: !burntFees.isEqualTo(ZERO),
};
}, [ withdrawalsData, totalReward, burntFees, txFees ]);
}, [ withdrawalsData, totalReward, burntFees, txFees, priorityFee ]);

return {
isLoading: withdrawalsIsLoading || queryIsLoading,
Expand All @@ -76,6 +84,7 @@ export const useKDABlockRewardsData = (query: BlockQuery): TKDABlockRewardsData
rewardAmount: calculatedValues?.rewardAmount ? BigNumber(calculatedValues.rewardAmount).toFixed() : undefined,
rewardBaseFee: calculatedValues?.rewardBaseFee ? BigNumber(calculatedValues.rewardBaseFee).toFixed() : undefined,
txFees: calculatedValues?.txFees ? BigNumber(calculatedValues.txFees).toFixed() : undefined,
priorityFee: calculatedValues?.priorityFee ? BigNumber(calculatedValues.priorityFee).toFixed() : undefined,
burntFees: calculatedValues?.burntFees ? BigNumber(calculatedValues.burntFees).toFixed() : undefined,
},
};
Expand Down
Loading