diff --git a/src/api/blocks.tsx b/src/api/blocks.tsx index 5a40bc9..2ee92db 100644 --- a/src/api/blocks.tsx +++ b/src/api/blocks.tsx @@ -104,6 +104,24 @@ export const blocks = { hash } } + rewardTransfers: unified_transaction( + where: { + type: { _eq: "IMMEDIATE" } + hash: { _is_null: true } + block: { + _or: [{ height: { _eq: $height } }, { hash: { _eq: $hash } }] + } + } + ) { + amount + detail_id + from { + id + } + to { + id + } + } } `; diff --git a/src/api/chain-status.tsx b/src/api/chain-status.tsx index 069eae4..03abc11 100644 --- a/src/api/chain-status.tsx +++ b/src/api/chain-status.tsx @@ -12,11 +12,22 @@ import { useHomeStatsDayWindows } from '@/utils/get-home-stats-day-windows'; import { useGetRecentDateRange } from '@/utils/get-recent-date-range'; +import { + EXCLUDE_REWARD_TRANSFERS, + withExcludedRewardTransfers +} from '@/utils/unified-transaction-filters'; const GET_HOME_STATS = gql` query GetHomeChainStats( - $startDate: timestamptz! - $endDate: timestamptz! + $last24HourWhere: unified_transaction_bool_exp! + $allTimeWhere: unified_transaction_bool_exp! + $transfersDay0Where: unified_transaction_bool_exp! + $transfersDay1Where: unified_transaction_bool_exp! + $transfersDay2Where: unified_transaction_bool_exp! + $transfersDay3Where: unified_transaction_bool_exp! + $transfersDay4Where: unified_transaction_bool_exp! + $transfersDay5Where: unified_transaction_bool_exp! + $transfersDay6Where: unified_transaction_bool_exp! $day0Start: timestamptz! $day0End: timestamptz! $day1Start: timestamptz! @@ -36,17 +47,13 @@ const GET_HOME_STATS = gql` block_height total_accounts total_deposit_accounts - total_executed_transfers - total_immediate_transfers - total_scheduled_transfers - total_cancelled_transfers } - last24Hour: transfer_aggregate( - where: { - timestamp: { _gte: $startDate, _lte: $endDate } - extrinsic_id: { _is_null: false } + last24Hour: unified_transaction_aggregate(where: $last24HourWhere) { + aggregate { + count } - ) { + } + allTimeTransactions: unified_transaction_aggregate(where: $allTimeWhere) { aggregate { count } @@ -58,12 +65,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay0: transfer_aggregate( - where: { - timestamp: { _gte: $day0Start, _lte: $day0End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay0: unified_transaction_aggregate(where: $transfersDay0Where) { aggregate { count } @@ -85,12 +87,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay1: transfer_aggregate( - where: { - timestamp: { _gte: $day1Start, _lte: $day1End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay1: unified_transaction_aggregate(where: $transfersDay1Where) { aggregate { count } @@ -112,12 +109,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay2: transfer_aggregate( - where: { - timestamp: { _gte: $day2Start, _lte: $day2End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay2: unified_transaction_aggregate(where: $transfersDay2Where) { aggregate { count } @@ -139,12 +131,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay3: transfer_aggregate( - where: { - timestamp: { _gte: $day3Start, _lte: $day3End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay3: unified_transaction_aggregate(where: $transfersDay3Where) { aggregate { count } @@ -166,12 +153,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay4: transfer_aggregate( - where: { - timestamp: { _gte: $day4Start, _lte: $day4End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay4: unified_transaction_aggregate(where: $transfersDay4Where) { aggregate { count } @@ -193,12 +175,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay5: transfer_aggregate( - where: { - timestamp: { _gte: $day5Start, _lte: $day5End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay5: unified_transaction_aggregate(where: $transfersDay5Where) { aggregate { count } @@ -220,12 +197,7 @@ const GET_HOME_STATS = gql` count } } - transfersDay6: transfer_aggregate( - where: { - timestamp: { _gte: $day6Start, _lte: $day6End } - extrinsic_id: { _is_null: false } - } - ) { + transfersDay6: unified_transaction_aggregate(where: $transfersDay6Where) { aggregate { count } @@ -290,8 +262,31 @@ export const chainStatus = { } return { - startDate, - endDate, + last24HourWhere: withExcludedRewardTransfers({ + timestamp: { _gte: startDate, _lte: endDate } + }), + allTimeWhere: EXCLUDE_REWARD_TRANSFERS, + transfersDay0Where: withExcludedRewardTransfers({ + timestamp: { _gte: day0.start, _lte: day0.end } + }), + transfersDay1Where: withExcludedRewardTransfers({ + timestamp: { _gte: day1.start, _lte: day1.end } + }), + transfersDay2Where: withExcludedRewardTransfers({ + timestamp: { _gte: day2.start, _lte: day2.end } + }), + transfersDay3Where: withExcludedRewardTransfers({ + timestamp: { _gte: day3.start, _lte: day3.end } + }), + transfersDay4Where: withExcludedRewardTransfers({ + timestamp: { _gte: day4.start, _lte: day4.end } + }), + transfersDay5Where: withExcludedRewardTransfers({ + timestamp: { _gte: day5.start, _lte: day5.end } + }), + transfersDay6Where: withExcludedRewardTransfers({ + timestamp: { _gte: day6.start, _lte: day6.end } + }), day0Start: day0.start, day0End: day0.end, day1Start: day1.start, diff --git a/src/api/unified-transactions.tsx b/src/api/unified-transactions.tsx index 54423dc..e28de69 100644 --- a/src/api/unified-transactions.tsx +++ b/src/api/unified-transactions.tsx @@ -12,6 +12,7 @@ import type { } from '@/schemas'; import type { PaginatedQueryVariables } from '@/types/query'; import { useGetRecentDateRange } from '@/utils/get-recent-date-range'; +import { EXCLUDE_REWARD_TRANSFERS } from '@/utils/unified-transaction-filters'; export const unifiedTransactions = { useGetAll: ( @@ -91,11 +92,13 @@ export const unifiedTransactions = { $limit: Int $offset: Int $orderBy: [unified_transaction_order_by!] + $where: unified_transaction_bool_exp ) { transactions: unified_transaction( limit: $limit offset: $offset order_by: $orderBy + where: $where ) { id type @@ -125,7 +128,8 @@ export const unifiedTransactions = { ...config, variables: { orderBy: { timestamp: 'desc' }, - limit: QUERY_RECENT_LIMIT + limit: QUERY_RECENT_LIMIT, + where: EXCLUDE_REWARD_TRANSFERS } } ); @@ -141,17 +145,15 @@ export const unifiedTransactions = { const GET_UNIFIED_TRANSACTIONS_STATS = gql` query GetUnifiedTransactionsStats( - $startDate: timestamptz! - $endDate: timestamptz! + $last24HourWhere: unified_transaction_bool_exp! + $allTimeWhere: unified_transaction_bool_exp! ) { - last24Hour: unified_transaction_aggregate( - where: { timestamp: { _gte: $startDate, _lte: $endDate } } - ) { + last24Hour: unified_transaction_aggregate(where: $last24HourWhere) { aggregate { totalCount: count } } - allTime: unified_transaction_aggregate { + allTime: unified_transaction_aggregate(where: $allTimeWhere) { aggregate { totalCount: count } @@ -164,8 +166,13 @@ export const unifiedTransactions = { { ...config, variables: { - startDate, - endDate + last24HourWhere: { + _and: [ + EXCLUDE_REWARD_TRANSFERS, + { timestamp: { _gte: startDate, _lte: endDate } } + ] + }, + allTimeWhere: EXCLUDE_REWARD_TRANSFERS } } ); diff --git a/src/components/common/table-columns/UNIFIED_LIST_TRANSACTION_COLUMNS.tsx b/src/components/common/table-columns/UNIFIED_LIST_TRANSACTION_COLUMNS.tsx index 6a6eb0c..908e75d 100644 --- a/src/components/common/table-columns/UNIFIED_LIST_TRANSACTION_COLUMNS.tsx +++ b/src/components/common/table-columns/UNIFIED_LIST_TRANSACTION_COLUMNS.tsx @@ -34,7 +34,7 @@ const columnHelper = createColumnHelper(); export const UNIFIED_LIST_TRANSACTION_COLUMNS = [ columnHelper.accessor((row) => row.hash ?? row.detail_id, { id: 'hash', - header: 'Hash / ID', + header: 'Hash', cell: (props) => { const row = props.row.original; const display = row.hash ?? row.detail_id; @@ -150,7 +150,7 @@ export const UNIFIED_LIST_TRANSACTION_COLUMNS = [ export const RECENT_UNIFIED_LIST_TRANSACTION_COLUMNS = [ columnHelper.accessor((row) => row.hash ?? row.detail_id, { id: 'hash', - header: 'Hash / ID', + header: 'Hash', cell: (props) => { const row = props.row.original; const display = row.hash ?? row.detail_id; diff --git a/src/components/features/account-details/account-all-transactions/hook.tsx b/src/components/features/account-details/account-all-transactions/hook.tsx index 275da8c..76ae6b6 100644 --- a/src/components/features/account-details/account-all-transactions/hook.tsx +++ b/src/components/features/account-details/account-all-transactions/hook.tsx @@ -10,6 +10,7 @@ import { useOrderBy } from '@/hooks/useOrderBy'; import { useTableState } from '@/hooks/useTableState'; import type { UnifiedListTransaction } from '@/schemas'; import { transformSortLiteral } from '@/utils/transform-sort'; +import { withExcludedRewardTransfers } from '@/utils/unified-transaction-filters'; export const useAccountAllTransactions = (accountId: string) => { const api = useApiClient(); @@ -27,12 +28,13 @@ export const useAccountAllTransactions = (accountId: string) => { const sortingValue = transformSortLiteral(orderBy); const where = useMemo( - () => ({ - _or: [ - { from: { id: { _eq: accountId } } }, - { to: { id: { _eq: accountId } } } - ] - }), + () => + withExcludedRewardTransfers({ + _or: [ + { from: { id: { _eq: accountId } } }, + { to: { id: { _eq: accountId } } } + ] + }), [accountId] ); diff --git a/src/components/features/block-details/block-information/BlockInformation.tsx b/src/components/features/block-details/block-information/BlockInformation.tsx index cf9f942..71e0710 100644 --- a/src/components/features/block-details/block-information/BlockInformation.tsx +++ b/src/components/features/block-details/block-information/BlockInformation.tsx @@ -6,7 +6,7 @@ import { LinkWithCopy } from '@/components/ui/composites/link-with-copy/LinkWith import { TextWithCopy } from '@/components/ui/composites/text-with-copy/TextWithCopy'; import { TimestampDisplay } from '@/components/ui/timestamp-display'; import { RESOURCES } from '@/constants/resources'; -import type { BlockResponse } from '@/schemas'; +import type { BlockResponse, BlockRewardTransfer } from '@/schemas'; import { formatBlockHeight, formatMonetaryValue } from '@/utils/formatter'; export interface BlockInformationProps { @@ -17,11 +17,30 @@ interface BlockDetails { height: number; hash: string; timestamp: string; - reward: number; + minerReward: string | null; + treasuryReward: string | null; miner: string; extrinsicsCount: number; } +function splitRewardTransfers( + transfers: BlockRewardTransfer[] | undefined, + minerId: string | undefined +) { + const rows = transfers ?? []; + const minerTransfer = minerId + ? rows.find((row) => row.to?.id === minerId) + : undefined; + const treasuryTransfers = rows.filter((row) => row !== minerTransfer); + + return { minerTransfer, treasuryTransfers }; +} + +function formatRewardAmount(amount: string | null | undefined) { + if (amount == null) return ; + return {formatMonetaryValue(amount)}; +} + export const BlockInformation: React.FC = ({ query }) => { @@ -30,13 +49,25 @@ export const BlockInformation: React.FC = ({ const extrinsicsCount = block?.extrinsics?.length ?? 0; const miner = data?.minerRewards?.[0]?.miner.id; + const minerRewardFallback = data?.minerRewards?.[0]?.reward; + const { minerTransfer, treasuryTransfers } = splitRewardTransfers( + data?.rewardTransfers, + miner + ); + const treasuryTransfer = treasuryTransfers[0]; + + const minerReward = + minerTransfer?.amount ?? + (minerRewardFallback != null ? String(minerRewardFallback) : null); + const treasuryReward = treasuryTransfer?.amount ?? null; const information: Partial[] = [ { height: block?.height, hash: block?.hash, miner, - reward: block?.reward, + minerReward, + treasuryReward, timestamp: block?.timestamp, extrinsicsCount } @@ -85,9 +116,14 @@ export const BlockInformation: React.FC = ({ ) }, { - label: 'Reward', - key: 'reward', - render: (value) => formatMonetaryValue(value) + label: 'Miner reward', + key: 'minerReward', + render: (value) => formatRewardAmount(value as string | null) + }, + { + label: 'Treasury reward', + key: 'treasuryReward', + render: (value) => formatRewardAmount(value as string | null) }, { label: 'Time', diff --git a/src/components/features/landing/hero/chain-stats/hook.tsx b/src/components/features/landing/hero/chain-stats/hook.tsx index 748b8bb..249c2c2 100644 --- a/src/components/features/landing/hero/chain-stats/hook.tsx +++ b/src/components/features/landing/hero/chain-stats/hook.tsx @@ -46,11 +46,7 @@ export const useChainStats = () => { const totalAccounts = status?.total_accounts ?? 0; const activeAccounts = totalAccounts - depositAccounts; - const totalTransactions = - (status?.total_immediate_transfers ?? 0) + - (status?.total_scheduled_transfers ?? 0) + - (status?.total_executed_transfers ?? 0) + - (status?.total_cancelled_transfers ?? 0); + const totalTransactions = data?.allTimeTransactions?.aggregate?.count ?? 0; const last24HourTransactions = data?.last24Hour?.aggregate?.count ?? 0; diff --git a/src/components/features/multisig-details/multisig-transactions/hook.tsx b/src/components/features/multisig-details/multisig-transactions/hook.tsx index 4851d8c..d4a558c 100644 --- a/src/components/features/multisig-details/multisig-transactions/hook.tsx +++ b/src/components/features/multisig-details/multisig-transactions/hook.tsx @@ -10,6 +10,7 @@ import { useOrderBy } from '@/hooks/useOrderBy'; import { useTableState } from '@/hooks/useTableState'; import type { UnifiedListTransaction } from '@/schemas'; import { transformSortLiteral } from '@/utils/transform-sort'; +import { withExcludedRewardTransfers } from '@/utils/unified-transaction-filters'; export const useMultisigDetailTransactions = (walletId: string) => { const api = useApiClient(); @@ -27,12 +28,13 @@ export const useMultisigDetailTransactions = (walletId: string) => { const sortingValue = transformSortLiteral(orderBy); const where = useMemo( - () => ({ - _or: [ - { from: { id: { _eq: walletId } } }, - { to: { id: { _eq: walletId } } } - ] - }), + () => + withExcludedRewardTransfers({ + _or: [ + { from: { id: { _eq: walletId } } }, + { to: { id: { _eq: walletId } } } + ] + }), [walletId] ); diff --git a/src/components/features/transaction-details/transaction-information/TransactionInformation.tsx b/src/components/features/transaction-details/transaction-information/TransactionInformation.tsx index 5ed5e47..8a3f0fd 100644 --- a/src/components/features/transaction-details/transaction-information/TransactionInformation.tsx +++ b/src/components/features/transaction-details/transaction-information/TransactionInformation.tsx @@ -126,7 +126,7 @@ export const TransactionInformation: React.FC = ({ data={extrinsicInfo} fields={[ { - label: 'Hash / ID', + label: 'Hash', key: 'id', render: (value) => value ? ( diff --git a/src/components/features/transaction-listing/transactions-table/hook.tsx b/src/components/features/transaction-listing/transactions-table/hook.tsx index ac651a9..b4d2e16 100644 --- a/src/components/features/transaction-listing/transactions-table/hook.tsx +++ b/src/components/features/transaction-listing/transactions-table/hook.tsx @@ -11,6 +11,7 @@ import { useOrderBy } from '@/hooks/useOrderBy'; import { useTableState } from '@/hooks/useTableState'; import type { UnifiedListTransaction } from '@/schemas'; import { transformSortLiteral } from '@/utils/transform-sort'; +import { withExcludedRewardTransfers } from '@/utils/unified-transaction-filters'; export const useTransactionsTable = () => { const api = useApiClient(); @@ -32,19 +33,19 @@ export const useTransactionsTable = () => { const where = useMemo(() => { if (accountId) { - return { + return withExcludedRewardTransfers({ _or: [ { from: { id: { _eq: accountId } } }, { to: { id: { _eq: accountId } } } ] - }; + }); } if (block) { - return { + return withExcludedRewardTransfers({ block_height: { _eq: Number(block) } - }; + }); } - return undefined; + return withExcludedRewardTransfers(); }, [accountId, block]); const { diff --git a/src/schemas/blocks.ts b/src/schemas/blocks.ts index d5184f7..417d76a 100644 --- a/src/schemas/blocks.ts +++ b/src/schemas/blocks.ts @@ -40,6 +40,13 @@ export interface BlockMinerReward { block: { height: number; hash: string }; } +export interface BlockRewardTransfer { + amount: string | null; + detail_id: string; + from: { id: string } | null; + to: { id: string } | null; +} + // Wormhole extrinsic for block response export interface BlockWormholeExtrinsic { id: string; @@ -58,6 +65,7 @@ export interface BlockWormholeExtrinsic { export interface BlockResponse { blocks: [Block]; minerRewards: BlockMinerReward[]; + rewardTransfers: BlockRewardTransfer[]; } export interface BlockListResponse { diff --git a/src/schemas/chain-status.ts b/src/schemas/chain-status.ts index 8a3e23a..d3e234a 100644 --- a/src/schemas/chain-status.ts +++ b/src/schemas/chain-status.ts @@ -1,3 +1,4 @@ +import type { Unified_Transaction_Bool_Exp } from '@/__generated__/graphql'; import type * as gql from '../__generated__/graphql'; export interface ChainStatus @@ -22,9 +23,16 @@ export interface AggregateCount { } | null; } +export interface HomeChainStatsStatus + extends Pick< + gql.Chain_Stats, + 'block_height' | 'total_accounts' | 'total_deposit_accounts' + > {} + export interface HomeChainStatsResponse { - status: ChainStatus | null; + status: HomeChainStatsStatus | null; last24Hour: AggregateCount; + allTimeTransactions: AggregateCount; blocksDay0: AggregateCount; blocksDay1: AggregateCount; blocksDay2: AggregateCount; @@ -49,8 +57,15 @@ export interface HomeChainStatsResponse { } export interface HomeChainStatsVariables { - startDate: string; - endDate: string; + last24HourWhere: Unified_Transaction_Bool_Exp; + allTimeWhere: Unified_Transaction_Bool_Exp; + transfersDay0Where: Unified_Transaction_Bool_Exp; + transfersDay1Where: Unified_Transaction_Bool_Exp; + transfersDay2Where: Unified_Transaction_Bool_Exp; + transfersDay3Where: Unified_Transaction_Bool_Exp; + transfersDay4Where: Unified_Transaction_Bool_Exp; + transfersDay5Where: Unified_Transaction_Bool_Exp; + transfersDay6Where: Unified_Transaction_Bool_Exp; day0Start: string; day0End: string; day1Start: string; diff --git a/src/utils/unified-transaction-filters.ts b/src/utils/unified-transaction-filters.ts new file mode 100644 index 0000000..ae33b23 --- /dev/null +++ b/src/utils/unified-transaction-filters.ts @@ -0,0 +1,15 @@ +import type { Unified_Transaction_Bool_Exp } from '@/__generated__/graphql'; + +/** Hashless IMMEDIATE rows are miner/treasury rewards, not user transactions. */ +export const EXCLUDE_REWARD_TRANSFERS = { + _not: { + _and: [{ type: { _eq: 'IMMEDIATE' } }, { hash: { _is_null: true } }] + } +} as const satisfies Unified_Transaction_Bool_Exp; + +export function withExcludedRewardTransfers( + where?: Unified_Transaction_Bool_Exp +): Unified_Transaction_Bool_Exp { + if (!where) return EXCLUDE_REWARD_TRANSFERS; + return { _and: [EXCLUDE_REWARD_TRANSFERS, where] }; +}