Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Celo: Block views customizations #2185

Merged
merged 17 commits into from
Aug 28, 2024
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
5 changes: 5 additions & 0 deletions icons/checkered_flag.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 23 additions & 2 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,16 @@ import type {
ArbitrumL2TxnBatchesItem,
} from 'types/api/arbitrumL2';
import type { TxBlobs, Blob } from 'types/api/blobs';
import type { BlocksResponse, BlockTransactionsResponse, Block, BlockFilters, BlockWithdrawalsResponse, BlockCountdownResponse } from 'types/api/block';
import type {
BlocksResponse,
BlockTransactionsResponse,
Block,
BlockFilters,
BlockWithdrawalsResponse,
BlockCountdownResponse,
BlockEpoch,
BlockEpochElectionRewardDetailsResponse,
} from 'types/api/block';
import type { ChartMarketResponse, ChartSecondaryCoinPriceResponse, ChartTransactionResponse } from 'types/api/charts';
import type { BackendVersionConfig } from 'types/api/configs';
import type {
Expand Down Expand Up @@ -322,6 +331,16 @@ export const RESOURCES = {
pathParams: [ 'height_or_hash' as const ],
filterFields: [],
},
block_epoch: {
path: '/api/v2/blocks/:height_or_hash/epoch',
pathParams: [ 'height_or_hash' as const ],
filterFields: [],
},
block_election_rewards: {
path: '/api/v2/blocks/:height_or_hash/election-rewards/:reward_type',
pathParams: [ 'height_or_hash' as const, 'reward_type' as const ],
filterFields: [],
},
txs_stats: {
path: '/api/v2/transactions/stats',
},
Expand Down Expand Up @@ -933,7 +952,7 @@ export interface ResourceError<T = unknown> {

export type ResourceErrorAccount<T> = ResourceError<{ errors: T }>

export type PaginatedResources = 'blocks' | 'block_txs' |
export type PaginatedResources = 'blocks' | 'block_txs' | 'block_election_rewards' |
'txs_validated' | 'txs_pending' | 'txs_with_blobs' | 'txs_watchlist' | 'txs_execution_node' |
'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' | 'tx_state_changes' | 'tx_blobs' |
'addresses' |
Expand Down Expand Up @@ -993,6 +1012,8 @@ Q extends 'block' ? Block :
Q extends 'block_countdown' ? BlockCountdownResponse :
Q extends 'block_txs' ? BlockTransactionsResponse :
Q extends 'block_withdrawals' ? BlockWithdrawalsResponse :
Q extends 'block_epoch' ? BlockEpoch :
Q extends 'block_election_rewards' ? BlockEpochElectionRewardDetailsResponse :
Q extends 'txs_stats' ? TransactionsStats :
Q extends 'txs_validated' ? TransactionsResponseValidated :
Q extends 'txs_pending' ? TransactionsResponsePending :
Expand Down
2 changes: 1 addition & 1 deletion lib/api/useApiFetch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type { ApiResource, ResourceName, ResourcePathParams } from './resources'

export interface Params<R extends ResourceName> {
pathParams?: ResourcePathParams<R>;
queryParams?: Record<string, string | Array<string> | number | boolean | undefined>;
queryParams?: Record<string, string | Array<string> | number | boolean | undefined | null>;
fetchParams?: Pick<FetchParams, 'body' | 'method' | 'signal' | 'headers'>;
}

Expand Down
43 changes: 43 additions & 0 deletions lib/api/useApiInfiniteQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type { InfiniteData, QueryKey, UseInfiniteQueryResult } from '@tanstack/react-query';
import { useInfiniteQuery, type UseInfiniteQueryOptions } from '@tanstack/react-query';

import type { PaginatedResources, ResourceError, ResourcePayload } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch';
import type { Params as ApiFetchParams } from 'lib/api/useApiFetch';

import { getResourceKey } from './useApiQuery';

type TQueryData<R extends PaginatedResources> = ResourcePayload<R>;
type TError = ResourceError<unknown>;
type TPageParam<R extends PaginatedResources> = ApiFetchParams<R>['queryParams'] | null;

export interface Params<R extends PaginatedResources> {
resourceName: R;
// eslint-disable-next-line max-len
queryOptions?: Omit<UseInfiniteQueryOptions<TQueryData<R>, TError, InfiniteData<TQueryData<R>>, TQueryData<R>, QueryKey, TPageParam<R>>, 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'>;
pathParams?: ApiFetchParams<R>['pathParams'];
}

type ReturnType<Resource extends PaginatedResources> = UseInfiniteQueryResult<InfiniteData<ResourcePayload<Resource>>, ResourceError<unknown>>;

export default function useApiInfiniteQuery<R extends PaginatedResources>({
resourceName,
queryOptions,
pathParams,
}: Params<R>): ReturnType<R> {
const apiFetch = useApiFetch();

return useInfiniteQuery<TQueryData<R>, TError, InfiniteData<TQueryData<R>>, QueryKey, TPageParam<R>>({
// eslint-disable-next-line @tanstack/query/exhaustive-deps
queryKey: getResourceKey(resourceName, { pathParams }),
queryFn: (context) => {
const queryParams = 'pageParam' in context ? (context.pageParam || undefined) : undefined;
return apiFetch(resourceName, { pathParams, queryParams }) as Promise<TQueryData<R>>;
},
initialPageParam: null,
getNextPageParam: (lastPage) => {
return lastPage.next_page_params as TPageParam<R>;
},
...queryOptions,
});
}
9 changes: 4 additions & 5 deletions lib/api/useApiQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { QueryKey, UseQueryOptions } from '@tanstack/react-query';
import type { UseQueryOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';

import type { Params as FetchParams } from 'lib/hooks/useFetch';
Expand All @@ -10,8 +10,7 @@ export interface Params<R extends ResourceName, E = unknown, D = ResourcePayload
pathParams?: ResourcePathParams<R>;
queryParams?: Record<string, string | Array<string> | number | boolean | undefined>;
fetchParams?: Pick<FetchParams, 'body' | 'method' | 'headers'>;
queryOptions?: Omit<UseQueryOptions<ResourcePayload<R>, ResourceError<E>, D>, 'queryKey' | 'queryFn'>;
queryKey?: QueryKey;
queryOptions?: Partial<Omit<UseQueryOptions<ResourcePayload<R>, ResourceError<E>, D>, 'queryFn'>>;
}

export function getResourceKey<R extends ResourceName>(resource: R, { pathParams, queryParams }: Params<R> = {}) {
Expand All @@ -24,13 +23,13 @@ export function getResourceKey<R extends ResourceName>(resource: R, { pathParams

export default function useApiQuery<R extends ResourceName, E = unknown, D = ResourcePayload<R>>(
resource: R,
{ queryOptions, pathParams, queryParams, queryKey, fetchParams }: Params<R, E, D> = {},
{ queryOptions, pathParams, queryParams, fetchParams }: Params<R, E, D> = {},
) {
const apiFetch = useApiFetch();

return useQuery<ResourcePayload<R>, ResourceError<E>, D>({
// eslint-disable-next-line @tanstack/query/exhaustive-deps
queryKey: queryKey || getResourceKey(resource, { pathParams, queryParams }),
queryKey: queryOptions?.queryKey || getResourceKey(resource, { pathParams, queryParams }),
queryFn: async({ signal }) => {
// all errors and error typing is handled by react-query
// so error response will never go to the data
Expand Down
33 changes: 33 additions & 0 deletions mocks/blocks/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import type { RpcBlock } from 'viem';

import type { Block, BlocksResponse } from 'types/api/block';

import { ZERO_ADDRESS } from 'lib/consts';

import * as addressMock from '../address/address';
import * as tokenMock from '../tokens/tokenInfo';

export const base: Block = {
base_fee_per_gas: '10000000000',
burnt_fees: '5449200000000000',
Expand Down Expand Up @@ -137,6 +142,34 @@ export const rootstock: Block = {
minimum_gas_price: '59240000',
};

export const celo: Block = {
...base,
celo: {
base_fee: {
token: tokenMock.tokenInfoERC20a,
amount: '445690000000000',
breakdown: [
{
address: addressMock.withName,
amount: '356552000000000.0000000000000',
percentage: 80,
},
{
address: {
...addressMock.withoutName,
hash: ZERO_ADDRESS,
},
amount: '89138000000000.0000000000000',
percentage: 20,
},
],
recipient: addressMock.contract,
},
epoch_number: 1486,
is_epoch_block: true,
},
};

export const withBlobTxs: Block = {
...base,
blob_gas_price: '21518435987',
Expand Down
57 changes: 57 additions & 0 deletions mocks/blocks/epoch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import _padStart from 'lodash/padStart';

import type { BlockEpoch, BlockEpochElectionRewardDetails, BlockEpochElectionRewardDetailsResponse } from 'types/api/block';

import * as addressMock from '../address/address';
import * as tokenMock from '../tokens/tokenInfo';
import * as tokenTransferMock from '../tokens/tokenTransfer';

export const blockEpoch1: BlockEpoch = {
number: 1486,
distribution: {
carbon_offsetting_transfer: tokenTransferMock.erc20,
community_transfer: tokenTransferMock.erc20,
reserve_bolster_transfer: null,
},
aggregated_election_rewards: {
delegated_payment: {
count: 0,
total: '71210001063118670575',
token: tokenMock.tokenInfoERC20d,
},
group: {
count: 10,
total: '157705500305820107521',
token: tokenMock.tokenInfoERC20b,
},
validator: {
count: 10,
total: '1348139501689262297152',
token: tokenMock.tokenInfoERC20c,
},
voter: {
count: 38,
total: '2244419545166303388',
token: tokenMock.tokenInfoERC20a,
},
},
};

function getRewardDetailsItem(index: number): BlockEpochElectionRewardDetails {
return {
amount: `${ 100 - index }210001063118670575`,
account: {
...addressMock.withoutName,
hash: `0x30D060F129817c4DE5fBc1366d53e19f43c8c6${ _padStart(String(index), 2, '0') }`,
},
associated_account: {
...addressMock.withoutName,
hash: `0x456f41406B32c45D59E539e4BBA3D7898c3584${ _padStart(String(index), 2, '0') }`,
},
};
}

export const electionRewardDetails1: BlockEpochElectionRewardDetailsResponse = {
items: Array(15).fill('').map((item, index) => getRewardDetailsItem(index)),
next_page_params: null,
};
1 change: 1 addition & 0 deletions public/icons/name.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
| "burger"
| "certified"
| "check"
| "checkered_flag"
| "clock-light"
| "clock"
| "coins/bitcoin"
Expand Down
24 changes: 23 additions & 1 deletion stubs/block.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Block } from 'types/api/block';
import type { Block, BlockEpochElectionReward, BlockEpoch } from 'types/api/block';

import { ADDRESS_PARAMS } from './addressParams';
import { TOKEN_INFO_ERC_20, TOKEN_TRANSFER_ERC_20 } from './token';

export const BLOCK_HASH = '0x8fa7b9e5e5e79deeb62d608db22ba9a5cb45388c7ebb9223ae77331c6080dc70';

Expand Down Expand Up @@ -35,3 +36,24 @@ export const BLOCK: Block = {
type: 'block',
uncles_hashes: [],
};

const BLOCK_EPOCH_REWARD: BlockEpochElectionReward = {
count: 10,
total: '157705500305820107521',
token: TOKEN_INFO_ERC_20,
};

export const BLOCK_EPOCH: BlockEpoch = {
number: 1486,
aggregated_election_rewards: {
group: BLOCK_EPOCH_REWARD,
validator: BLOCK_EPOCH_REWARD,
voter: BLOCK_EPOCH_REWARD,
delegated_payment: BLOCK_EPOCH_REWARD,
},
distribution: {
carbon_offsetting_transfer: TOKEN_TRANSFER_ERC_20,
community_transfer: TOKEN_TRANSFER_ERC_20,
reserve_bolster_transfer: TOKEN_TRANSFER_ERC_20,
},
};
3 changes: 2 additions & 1 deletion stubs/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import type { TokenInstanceTransferPagination, TokenInstanceTransferResponse } f
import type { TokenTransfer, TokenTransferPagination, TokenTransferResponse } from 'types/api/tokenTransfer';

import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';
import { BLOCK_HASH } from './block';
import { TX_HASH } from './tx';
import { generateListStub } from './utils';

export const BLOCK_HASH = '0x8fa7b9e5e5e79deeb62d608db22ba9a5cb45388c7ebb9223ae77331c6080dc70';

export const TOKEN_INFO_ERC_20: TokenInfo<'ERC-20'> = {
address: ADDRESS_HASH,
circulating_market_cap: '117629601.61913824',
Expand Down
1 change: 1 addition & 0 deletions theme/foundations/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const colors = {
facebook: '#4460A0',
medium: '#231F20',
reddit: '#FF4500',
celo: '#FCFF52',
};

export default colors;
47 changes: 47 additions & 0 deletions types/api/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ import type { Reward } from 'types/api/reward';
import type { Transaction } from 'types/api/transaction';

import type { ArbitrumBatchStatus, ArbitrumL2TxData } from './arbitrumL2';
import type { TokenInfo } from './token';
import type { TokenTransfer } from './tokenTransfer';
import type { ZkSyncBatchesItem } from './zkSyncL2';

export type BlockType = 'block' | 'reorg' | 'uncle';

export interface BlockBaseFeeCelo {
amount: string;
breakdown: Array<{ amount: string; percentage: number; address: AddressParam }>;
recipient: AddressParam;
token: TokenInfo;
}

export interface Block {
height: number;
timestamp: string;
Expand Down Expand Up @@ -50,6 +59,12 @@ export interface Block {
'batch_number': number | null;
};
arbitrum?: ArbitrumBlockData;
// CELO FIELDS
celo?: {
epoch_number: number;
is_epoch_block: boolean;
base_fee?: BlockBaseFeeCelo;
};
}

type ArbitrumBlockData = {
Expand Down Expand Up @@ -112,3 +127,35 @@ export interface BlockCountdownResponse {
RemainingBlock: string;
} | null;
}

export interface BlockEpochElectionReward {
count: number;
token: TokenInfo<'ERC-20'>;
total: string;
}

export interface BlockEpoch {
number: number;
distribution: {
carbon_offsetting_transfer: TokenTransfer | null;
community_transfer: TokenTransfer | null;
reserve_bolster_transfer: TokenTransfer | null;
};
aggregated_election_rewards: {
delegated_payment: BlockEpochElectionReward | null;
group: BlockEpochElectionReward | null;
validator: BlockEpochElectionReward | null;
voter: BlockEpochElectionReward | null;
};
}

export interface BlockEpochElectionRewardDetails {
account: AddressParam;
amount: string;
associated_account: AddressParam;
}

export interface BlockEpochElectionRewardDetailsResponse {
items: Array<BlockEpochElectionRewardDetails>;
next_page_params: null;
}
3 changes: 3 additions & 0 deletions types/api/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export type HomeStats = {
rootstock_locked_btc?: string | null;
last_output_root_size?: string | null;
secondary_coin_price?: string | null;
celo?: {
epoch_number: number;
};
}

export type GasPrices = {
Expand Down
Loading
Loading