Skip to content
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
21 changes: 21 additions & 0 deletions configs/app/features/hotContracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Feature } from './types';

import { getEnvValue } from '../utils';

const title = 'Hot contracts';

const config: Feature<{ isEnabled: true }> = (() => {
if (getEnvValue('NEXT_PUBLIC_HOT_CONTRACTS_ENABLED') === 'true') {
return Object.freeze({
title,
isEnabled: true,
});
}

return Object.freeze({
title,
isEnabled: false,
});
})();

export default config;
1 change: 1 addition & 0 deletions configs/app/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export { default as gasTracker } from './gasTracker';
export { default as getGasButton } from './getGasButton';
export { default as googleAnalytics } from './googleAnalytics';
export { default as growthBook } from './growthBook';
export { default as hotContracts } from './hotContracts';
export { default as marketplace } from './marketplace';
export { default as megaEth } from './megaEth';
export { default as metasuites } from './metasuites';
Expand Down
1 change: 1 addition & 0 deletions configs/envs/.env.main
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ NEXT_PUBLIC_HAS_USER_OPS=true
NEXT_PUBLIC_HELIA_VERIFIED_FETCH_ENABLED=false
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(51, 53, 67, 1)'],'text_color':['rgba(165, 252, 122, 1)']}
NEXT_PUBLIC_HOT_CONTRACTS_ENABLED=true
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
Expand Down
1 change: 1 addition & 0 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const schema = yup
return isUndefined || valueSchema.isValidSync(data);
}),
NEXT_PUBLIC_FLASHBLOCKS_SOCKET_URL: yup.string().test(urlTest),
NEXT_PUBLIC_HOT_CONTRACTS_ENABLED: yup.boolean(),

// Misc
NEXT_PUBLIC_USE_NEXT_JS_PROXY: yup.boolean(),
Expand Down
1 change: 1 addition & 0 deletions deploy/tools/envs-validator/test/.env.base
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ NEXT_PUBLIC_MAX_CONTENT_WIDTH_ENABLED=false
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_STATS=['total_blocks','average_block_time','total_txs','wallet_addresses','gas_tracker','current_epoch']
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['lightpink'],'text_color':['deepskyblue','white'],'border':['3px solid black']}
NEXT_PUBLIC_HOT_CONTRACTS_ENABLED=true
NEXT_PUBLIC_GAS_TRACKER_ENABLED=true
NEXT_PUBLIC_GAS_TRACKER_UNITS=['gwei']
NEXT_PUBLIC_IS_TESTNET=true
Expand Down
10 changes: 10 additions & 0 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,16 @@ This feature enables Blockscout Merits program. It requires that the [My account

&nbsp;

### Hot contract

Show the page with aggregate metrics for the most popular contracts.

| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_HOT_CONTRACTS_ENABLED | `boolean` | Set to true to enable the feature | Required | - | `true` | upcoming |

&nbsp;

### Flashblocks

This feature allows users to view [Flashblocks](https://docs.base.org/base-chain/flashblocks/apps)-related content in the explorer, including the Flashblocks real-time feed. It currently supports only Base chains.
Expand Down
11 changes: 2 additions & 9 deletions icons/gas.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions icons/gas_slim.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions icons/hot-contracts.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions lib/api/services/general/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { Blob } from 'types/api/blobs';
import type { Block } from 'types/api/block';
import type { ChartMarketResponse, ChartSecondaryCoinPriceResponse, ChartTransactionResponse } from 'types/api/charts';
import type { BackendVersionConfig, CeloConfig, CsvExportConfig } from 'types/api/configs';
import type { HotContractsFilters, HotContractsResponse, HotContractsSorting } from 'types/api/contracts';
import type { DepositsResponse, DepositsCounters } from 'types/api/deposits';
import type { CeloEpochDetails, CeloEpochElectionRewardDetailsResponse, CeloEpochListResponse } from 'types/api/epochs';
import type { IndexingStatus } from 'types/api/indexingStatus';
Expand Down Expand Up @@ -75,6 +76,11 @@ export const GENERAL_API_MISC_RESOURCES = {
stats_charts_secondary_coin_price: {
path: '/api/v2/stats/charts/secondary-coin-market',
},
stats_hot_contracts: {
path: '/api/v2/stats/hot-smart-contracts',
paginated: true,
filterFields: [ 'scale' as const ],
},

// HOMEPAGE
homepage_blocks: {
Expand Down Expand Up @@ -271,6 +277,7 @@ R extends 'general:stats' ? HomeStats :
R extends 'general:stats_charts_txs' ? ChartTransactionResponse :
R extends 'general:stats_charts_market' ? ChartMarketResponse :
R extends 'general:stats_charts_secondary_coin_price' ? ChartSecondaryCoinPriceResponse :
R extends 'general:stats_hot_contracts' ? HotContractsResponse :
R extends 'general:homepage_blocks' ? Array<Block> :
R extends 'general:homepage_txs' ? Array<Transaction> :
R extends 'general:homepage_txs_watchlist' ? Array<Transaction> :
Expand Down Expand Up @@ -316,6 +323,7 @@ never;

/* eslint-disable @stylistic/indent */
export type GeneralApiMiscPaginationFilters<R extends GeneralApiMiscResourceName> =
R extends 'general:stats_hot_contracts' ? HotContractsFilters :
R extends 'general:search' ? SearchResultFilters :
R extends 'general:user_ops' ? UserOpsFilters :
R extends 'general:validators_stability' ? ValidatorsStabilityFilters :
Expand All @@ -325,6 +333,7 @@ never;

/* eslint-disable @stylistic/indent */
export type GeneralApiMiscPaginationSorting<R extends GeneralApiMiscResourceName> =
R extends 'general:stats_hot_contracts' ? HotContractsSorting :
R extends 'general:validators_stability' ? ValidatorsStabilitySorting :
R extends 'general:validators_blackfort' ? ValidatorsBlackfortSorting :
never;
Expand Down
62 changes: 29 additions & 33 deletions lib/hooks/useNavItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,42 +261,43 @@ export default function useNavItems(): ReturnType {
].filter(Boolean);

const statsNavItem = (() => {
const uptimeItem = {
text: 'Uptime',
nextRoute: { pathname: '/uptime' as const },
icon: 'refresh_menu',
isActive: pathname.startsWith('/uptime'),
};

if (config.features.stats.isEnabled && config.features.megaEth.isEnabled) {
return {
text: 'Charts & stats',
icon: 'stats',
isActive: pathname.startsWith('/stats') || pathname.startsWith('/uptime'),
subItems: [
{
text: `${ config.chain.name } stats`,
nextRoute: { pathname: '/stats' as const },
icon: 'graph',
isActive: pathname.startsWith('/stats/'),
},
uptimeItem,
],
};
}
const items = [
config.features.stats.isEnabled && {
text: 'Chain stats',
nextRoute: { pathname: '/stats' as const },
icon: 'graph',
isActive: pathname.startsWith('/stats'),
},
config.features.megaEth.isEnabled && {
text: 'Uptime',
nextRoute: { pathname: '/uptime' as const },
icon: 'refresh_menu',
isActive: pathname.startsWith('/uptime'),
},
config.features.hotContracts.isEnabled && {
text: 'Hot contracts',
nextRoute: { pathname: '/hot-contracts' as const },
icon: 'hot-contracts',
isActive: pathname.startsWith('/hot-contracts'),
},
config.features.gasTracker.isEnabled && {
text: 'Gas tracker',
nextRoute: { pathname: '/gas-tracker' as const },
icon: 'gas',
isActive: pathname.startsWith('/gas-tracker'),
},
].filter(Boolean);

if (!config.features.stats.isEnabled) {
if (config.features.megaEth.isEnabled) {
return uptimeItem;
}
if (items.length === 0) {
return null;
}

return {
text: 'Charts & stats',
nextRoute: { pathname: '/stats' as const },
icon: 'stats',
isActive: pathname.startsWith('/stats'),
isActive: items.some(item => isInternalItem(item) && item.isActive),
subItems: items,
};
})();

Expand All @@ -316,11 +317,6 @@ export default function useNavItems(): ReturnType {
nextRoute: { pathname: '/contract-verification' as const },
isActive: pathname.startsWith('/contract-verification'),
},
config.features.gasTracker.isEnabled && {
text: 'Gas tracker',
nextRoute: { pathname: '/gas-tracker' as const },
isActive: pathname.startsWith('/gas-tracker'),
},
config.features.publicTagsSubmission.isEnabled && {
text: 'Submit public tag',
nextRoute: { pathname: '/public-tags/submit' as const },
Expand Down
1 change: 1 addition & 0 deletions lib/metadata/getPageOgType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const OG_TYPE_DICT: Record<Route['pathname'], OGPageType> = {
'/stats': 'Root page',
'/stats/[id]': 'Regular page',
'/uptime': 'Root page',
'/hot-contracts': 'Root page',
'/api-docs': 'Regular page',
'/search-results': 'Regular page',
'/auth/profile': 'Root page',
Expand Down
1 change: 1 addition & 0 deletions lib/metadata/templates/description.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/stats': DEFAULT_TEMPLATE,
'/stats/[id]': DEFAULT_TEMPLATE,
'/uptime': DEFAULT_TEMPLATE,
'/hot-contracts': DEFAULT_TEMPLATE,
'/api-docs': DEFAULT_TEMPLATE,
'/search-results': DEFAULT_TEMPLATE,
'/auth/profile': DEFAULT_TEMPLATE,
Expand Down
1 change: 1 addition & 0 deletions lib/metadata/templates/title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const TEMPLATE_MAP: Record<Route['pathname'], string> = {
'/stats': '%network_name% stats - %network_name% network insights',
'/stats/[id]': '%network_name% stats - %id% chart',
'/uptime': '%network_name% uptime',
'/hot-contracts': '%network_name% hot contracts',
'/api-docs': '%network_name% API docs - %network_name% developer tools',
'/search-results': '%network_name% search result for %q%',
'/auth/profile': '%network_name% - my profile',
Expand Down
1 change: 1 addition & 0 deletions lib/mixpanel/getPageType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const PAGE_TYPE_DICT: Record<Route['pathname'], string> = {
'/stats': 'Stats',
'/stats/[id]': 'Stats chart',
'/uptime': 'Uptime',
'/hot-contracts': 'Hot contracts',
'/api-docs': 'REST API',
'/search-results': 'Search results',
'/auth/profile': 'Profile',
Expand Down
33 changes: 32 additions & 1 deletion mocks/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { VerifiedContract, VerifiedContractsResponse } from 'types/api/contracts';
import type { HotContractsResponse, VerifiedContract, VerifiedContractsResponse } from 'types/api/contracts';

export const contract1: VerifiedContract = {
address: {
Expand Down Expand Up @@ -83,3 +83,34 @@ export const baseResponse: VerifiedContractsResponse = {
smart_contract_id: '172',
},
};

export const hotContractsResponse: HotContractsResponse = {
items: [
{
contract_address: { ...contract1.address, name: null, reputation: 'scam' },
balance: '1000000000000000000',
transactions_count: '1000',
total_gas_used: '100000000',
},
{
contract_address: {
...contract2.address,
metadata: {
reputation: null,
tags: [
{ tagType: 'protocol', name: 'Goose', slug: 'goose', ordinal: 1, meta: null },
],
},
},
balance: '420',
transactions_count: '42',
total_gas_used: '12343566',
},
],
next_page_params: {
items_count: '50',
transactions_count: '50',
total_gas_used: '50',
contract_address_hash: '50',
},
};
8 changes: 8 additions & 0 deletions nextjs/getServerSideProps/guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ export const gasTracker: Guard = (chainConfig: typeof config) => async() => {
}
};

export const hotContracts: Guard = (chainConfig: typeof config) => async() => {
if (!chainConfig.features.hotContracts.isEnabled) {
return {
notFound: true,
};
}
};

export const advancedFilter: Guard = (chainConfig: typeof config) => async() => {
if (!chainConfig.features.advancedFilter.isEnabled) {
return {
Expand Down
1 change: 1 addition & 0 deletions nextjs/getServerSideProps/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const accountsLabelSearch = factory([ guards.accountsLabelSearch ]);
export const validators = factory([ guards.validators ]);
export const validatorDetails = factory([ guards.validatorDetails ]);
export const gasTracker = factory([ guards.gasTracker ]);
export const hotContracts = factory([ guards.hotContracts ]);
export const advancedFilter = factory([ guards.advancedFilter ]);
export const dataAvailability = factory([ guards.dataAvailability ]);
export const login = factory([ guards.login ]);
Expand Down
1 change: 1 addition & 0 deletions nextjs/nextjs-routes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ declare module "nextjs-routes" {
| StaticRoute<"/epochs">
| DynamicRoute<"/essential-dapps/[id]", { "id": string }>
| StaticRoute<"/gas-tracker">
| StaticRoute<"/hot-contracts">
| StaticRoute<"/">
| StaticRoute<"/internal-txs">
| StaticRoute<"/interop-messages">
Expand Down
19 changes: 19 additions & 0 deletions pages/hot-contracts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import React from 'react';

import PageNextJs from 'nextjs/PageNextJs';

const HotContracts = dynamic(() => import('ui/pages/HotContracts'), { ssr: false });

const Page: NextPage = () => {
return (
<PageNextJs pathname="/hot-contracts">
<HotContracts/>
</PageNextJs>
);
};

export default Page;

export { hotContracts as getServerSideProps } from 'nextjs/getServerSideProps/main';
2 changes: 2 additions & 0 deletions public/icons/name.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
| "flame"
| "flashblock"
| "games"
| "gas_slim"
| "gas_xl"
| "gas"
| "gear_slim"
Expand All @@ -86,6 +87,7 @@
| "heart_filled"
| "heart_outline"
| "hexagon"
| "hot-contracts"
| "hourglass_slim"
| "hourglass"
| "info_filled"
Expand Down
9 changes: 8 additions & 1 deletion stubs/contract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type * as stats from '@blockscout/stats-types';
import type { SmartContract, SmartContractMudSystemsResponse } from 'types/api/contract';
import type { VerifiedContract, VerifiedContractsCounters } from 'types/api/contracts';
import type { HotContract, VerifiedContract, VerifiedContractsCounters } from 'types/api/contracts';

import type { SolidityScanReport } from 'lib/solidityScan/schema';

Expand Down Expand Up @@ -117,3 +117,10 @@ export const MUD_SYSTEMS: SmartContractMudSystemsResponse = {
},
],
};

export const HOT_CONTRACTS: HotContract = {
contract_address: VERIFIED_CONTRACT_INFO.address,
balance: '1000000000000000000',
transactions_count: '1000',
total_gas_used: '100000000',
};
Loading
Loading