diff --git a/configs/app/features/beaconChain.ts b/configs/app/features/beaconChain.ts index 3e9695482f..e2da16bb49 100644 --- a/configs/app/features/beaconChain.ts +++ b/configs/app/features/beaconChain.ts @@ -4,9 +4,10 @@ import { getEnvValue } from '../utils'; const title = 'Beacon chain'; -const config: Feature<{ currency: { symbol: string }; validatorUrlTemplate: string | undefined }> = (() => { +const config: Feature<{ currency: { symbol: string }; validatorUrlTemplate: string | undefined; withdrawalsOnly: boolean }> = (() => { if (getEnvValue('NEXT_PUBLIC_HAS_BEACON_CHAIN') === 'true') { const validatorUrlTemplate = getEnvValue('NEXT_PUBLIC_BEACON_CHAIN_VALIDATOR_URL_TEMPLATE'); + const withdrawalsOnly = getEnvValue('NEXT_PUBLIC_BEACON_CHAIN_WITHDRAWALS_ONLY') === 'true'; return Object.freeze({ title, isEnabled: true, @@ -17,6 +18,7 @@ const config: Feature<{ currency: { symbol: string }; validatorUrlTemplate: stri '', // maybe we need some other default value here }, validatorUrlTemplate, + withdrawalsOnly, }); } diff --git a/deploy/tools/envs-validator/schemas/features/beaconChain.ts b/deploy/tools/envs-validator/schemas/features/beaconChain.ts index 6cc634af85..63ee48d4bd 100644 --- a/deploy/tools/envs-validator/schemas/features/beaconChain.ts +++ b/deploy/tools/envs-validator/schemas/features/beaconChain.ts @@ -4,6 +4,17 @@ export const beaconChainSchema = yup .object() .shape({ NEXT_PUBLIC_HAS_BEACON_CHAIN: yup.boolean(), + NEXT_PUBLIC_BEACON_CHAIN_WITHDRAWALS_ONLY: yup + .boolean() + .when('NEXT_PUBLIC_HAS_BEACON_CHAIN', { + is: (value: boolean) => value, + then: (schema) => schema, + otherwise: (schema) => schema.test( + 'not-exist', + 'NEXT_PUBLIC_BEACON_CHAIN_WITHDRAWALS_ONLY can only be used if NEXT_PUBLIC_HAS_BEACON_CHAIN is set to "true"', + value => value === undefined, + ), + }), NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL: yup .string() .when('NEXT_PUBLIC_HAS_BEACON_CHAIN', { diff --git a/deploy/tools/sitemap-generator/next-sitemap.config.js b/deploy/tools/sitemap-generator/next-sitemap.config.js index 90fe3579cf..753ff474cd 100644 --- a/deploy/tools/sitemap-generator/next-sitemap.config.js +++ b/deploy/tools/sitemap-generator/next-sitemap.config.js @@ -82,7 +82,7 @@ module.exports = { break; case '/batches': case '/deposits': - if (!process.env.NEXT_PUBLIC_ROLLUP_TYPE) { + if (!process.env.NEXT_PUBLIC_ROLLUP_TYPE && (process.env.NEXT_PUBLIC_HAS_BEACON_CHAIN !== 'true' || process.env.NEXT_PUBLIC_BEACON_CHAIN_WITHDRAWALS_ONLY === 'true')) { return null; } break; diff --git a/docs/ENVS.md b/docs/ENVS.md index 4b0bc5793a..a262c94639 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -507,6 +507,7 @@ Ads are enabled by default on all self-hosted instances. If you would like to di | Variable | Type| Description | Compulsoriness | Default value | Example value | Version | | --- | --- | --- | --- | --- | --- | --- | | NEXT_PUBLIC_HAS_BEACON_CHAIN | `boolean` | Set to true for networks with the beacon chain | Required | - | `true` | v1.0.x+ | +| NEXT_PUBLIC_BEACON_CHAIN_WITHDRAWALS_ONLY | `boolean` | Set to true for networks that have only withdrawals (no deposits) | - | - | `true` | v2.6.0+ | | NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL | `string` | Beacon network currency symbol | - | `NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL` | `ETH` | v1.0.x+ | | NEXT_PUBLIC_BEACON_CHAIN_VALIDATOR_URL_TEMPLATE | `string` | Url template to build a link to validator. Should contain `{pk}` string that will be replaced with the validator's public key | - | - | `https://example.com/beacon/{pk}/validator` | v2.3.0+ | diff --git a/lib/hooks/useNavItems.tsx b/lib/hooks/useNavItems.tsx index 29bfcfd3b3..f510851ced 100644 --- a/lib/hooks/useNavItems.tsx +++ b/lib/hooks/useNavItems.tsx @@ -7,6 +7,7 @@ import config from 'configs/app'; import { rightLineArrow } from 'toolkit/utils/htmlEntities'; const marketplaceFeature = config.features.marketplace; +const beaconChainFeature = config.features.beaconChain; interface ReturnType { mainNavItems: Array; @@ -224,7 +225,7 @@ export default function useNavItems(): ReturnType { validators, verifiedContracts, nameLookup, - config.features.beaconChain.isEnabled && { + beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly && { text: 'Deposits', nextRoute: { pathname: '/deposits' as const }, icon: 'navigation/deposits', diff --git a/nextjs/getServerSideProps/guards.ts b/nextjs/getServerSideProps/guards.ts index c2b6d6d53c..4ea9786922 100644 --- a/nextjs/getServerSideProps/guards.ts +++ b/nextjs/getServerSideProps/guards.ts @@ -218,8 +218,9 @@ export const rollup: Guard = (chainConfig: typeof config) => async() => { const DEPOSITS_ROLLUP_TYPES: Array = [ 'optimistic', 'shibarium', 'zkEvm', 'arbitrum', 'scroll' ]; export const deposits: Guard = (chainConfig: typeof config) => async() => { const rollupFeature = chainConfig.features.rollup; + const beaconChainFeature = chainConfig.features.beaconChain; if ( - !chainConfig.features.beaconChain.isEnabled && + (!beaconChainFeature.isEnabled || beaconChainFeature.withdrawalsOnly) && !(rollupFeature.isEnabled && DEPOSITS_ROLLUP_TYPES.includes(rollupFeature.type))) { return { notFound: true, diff --git a/pages/deposits/index.tsx b/pages/deposits/index.tsx index e05534b6f9..643737c982 100644 --- a/pages/deposits/index.tsx +++ b/pages/deposits/index.tsx @@ -29,7 +29,7 @@ const Deposits = dynamic(() => { return import('ui/pages/ScrollL2Deposits'); } - if (beaconChainFeature.isEnabled) { + if (beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly) { return import('ui/pages/BeaconChainDeposits'); } diff --git a/ui/block/useBlockDepositsQuery.tsx b/ui/block/useBlockDepositsQuery.tsx index 91422327f7..b3e7332ae5 100644 --- a/ui/block/useBlockDepositsQuery.tsx +++ b/ui/block/useBlockDepositsQuery.tsx @@ -16,6 +16,8 @@ interface Params { tab: string; } +const beaconChainFeature = config.features.beaconChain; + // No deposits data in RPC, so we use API only export default function useBlockDepositsQuery({ heightOrHash, blockQuery, tab }: Params): BlockDepositsQuery { const apiQuery = useQueryWithPages({ @@ -24,7 +26,7 @@ export default function useBlockDepositsQuery({ heightOrHash, blockQuery, tab }: options: { enabled: tab === 'deposits' && - config.features.beaconChain.isEnabled && + beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly && !blockQuery.isPlaceholderData && !blockQuery.isDegradedData, placeholderData: generateListStub<'general:block_deposits'>(DEPOSIT, 50, { next_page_params: { index: 5, diff --git a/ui/deposits/beaconChain/BeaconChainDepositsListItem.tsx b/ui/deposits/beaconChain/BeaconChainDepositsListItem.tsx index 14afd1ab15..bce646e5f4 100644 --- a/ui/deposits/beaconChain/BeaconChainDepositsListItem.tsx +++ b/ui/deposits/beaconChain/BeaconChainDepositsListItem.tsx @@ -22,7 +22,7 @@ type Props = { }; const BeaconChainDepositsListItem = ({ item, isLoading, view }: Props) => { - if (!feature.isEnabled) { + if (!feature.isEnabled || feature.withdrawalsOnly) { return null; } diff --git a/ui/deposits/beaconChain/BeaconChainDepositsTable.tsx b/ui/deposits/beaconChain/BeaconChainDepositsTable.tsx index c911f58cb8..7e278c29ba 100644 --- a/ui/deposits/beaconChain/BeaconChainDepositsTable.tsx +++ b/ui/deposits/beaconChain/BeaconChainDepositsTable.tsx @@ -21,7 +21,7 @@ type Props = { const BeaconChainDepositsTable = ({ items, isLoading, top, view }: Props) => { const { cutRef, renderedItemsNum } = useLazyRenderedList(items, !isLoading); - if (!feature.isEnabled) { + if (!feature.isEnabled || feature.withdrawalsOnly) { return null; } diff --git a/ui/pages/Address.tsx b/ui/pages/Address.tsx index f0a1c9a2c4..46013676ef 100644 --- a/ui/pages/Address.tsx +++ b/ui/pages/Address.tsx @@ -70,6 +70,7 @@ const txInterpretation = config.features.txInterpretation; const addressProfileAPIFeature = config.features.addressProfileAPI; const xScoreFeature = config.features.xStarScore; const nameServicesFeature = config.features.nameServices; +const beaconChainFeature = config.features.beaconChain; const AddressPageContent = () => { const router = useRouter(); @@ -231,7 +232,7 @@ const AddressPageContent = () => { component: , } : undefined, - config.features.beaconChain.isEnabled && addressTabsCountersQuery.data?.beacon_deposits_count ? + beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly && addressTabsCountersQuery.data?.beacon_deposits_count ? { id: 'deposits', title: 'Deposits', diff --git a/ui/pages/BeaconChainDeposits.tsx b/ui/pages/BeaconChainDeposits.tsx index a9435589de..320fbfe05b 100644 --- a/ui/pages/BeaconChainDeposits.tsx +++ b/ui/pages/BeaconChainDeposits.tsx @@ -60,7 +60,7 @@ const BeaconChainDeposits = () => { ) : null; const text = (() => { - if (countersQuery.isError || !feature.isEnabled) { + if (countersQuery.isError || !feature.isEnabled || feature.withdrawalsOnly) { return null; } diff --git a/ui/pages/Block.tsx b/ui/pages/Block.tsx index 5158db9af1..554a464cfb 100644 --- a/ui/pages/Block.tsx +++ b/ui/pages/Block.tsx @@ -46,6 +46,8 @@ const TAB_LIST_PROPS = { }; const TABS_HEIGHT = 88; +const beaconChainFeature = config.features.beaconChain; + const BlockPageContent = () => { const router = useRouter(); const isMobile = useIsMobile(); @@ -109,7 +111,7 @@ const BlockPageContent = () => { ), } : null, - config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.beacon_deposits_count) ? + beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly && Boolean(blockQuery.data?.beacon_deposits_count) ? { id: 'deposits', title: 'Deposits',