From 751e2e3659b01d42c8daa926b45819eb7819c215 Mon Sep 17 00:00:00 2001 From: tom goriunov Date: Wed, 9 Aug 2023 15:39:36 -0400 Subject: [PATCH] app feature list (#1079) * metadata helpers and values for txs pages * update titles to the rest of the pages * refactor getServerSideProps * dynamically update metadata for token and dapp page * test * 404 error page * make new config * make use of new config, delete old one * feature reporter: dev implementation * feature reporter: docker integration * resctructure ENVS.md * sentry feature * refinements * add spaces between sections * tweaks * switch to camelCase * clean up * remove NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS * v --- .eslintrc.js | 4 +- Dockerfile | 16 + configs/app/api.ts | 23 + configs/app/app.ts | 23 + configs/app/chain.ts | 19 + configs/app/config.ts | 213 ---- configs/app/features/account.ts | 33 + configs/app/features/addressVerification.ts | 14 + configs/app/features/adsBanner.ts | 23 + configs/app/features/adsText.ts | 16 + configs/app/features/beaconChain.ts | 9 + configs/app/features/blockchainInteraction.ts | 22 + configs/app/features/csvExport.ts | 11 + configs/app/features/googleAnalytics.ts | 9 + configs/app/features/graphqlApiDocs.ts | 9 + configs/app/features/index.ts | 18 + configs/app/features/marketplace.ts | 12 + configs/app/features/mixpanel.ts | 9 + configs/app/features/restApiDocs.ts | 9 + configs/app/features/rollup.ts | 8 + configs/app/features/sentry.ts | 13 + configs/app/features/sol2uml.ts | 12 + configs/app/features/stats.ts | 12 + configs/app/features/verifiedTokens.ts | 12 + configs/app/features/web3Wallet.ts | 23 + configs/app/index.ts | 17 + configs/app/services.ts | 7 + configs/app/ui.ts | 45 + configs/app/utils.ts | 9 + configs/envs/.env.eth | 42 +- configs/envs/.env.eth_goerli | 45 +- configs/envs/.env.jest | 55 +- configs/envs/.env.localhost | 36 +- configs/envs/.env.main | 49 +- configs/envs/.env.main.L2 | 52 +- configs/envs/.env.poa_core | 46 +- configs/envs/.env.pw | 53 +- configs/sentry/react.ts | 10 +- deploy/scripts/entrypoint.sh | 5 +- deploy/tools/envs-validator/index.ts | 8 +- deploy/tools/feature-reporter/.gitignore | 3 + deploy/tools/feature-reporter/dev.sh | 6 + deploy/tools/feature-reporter/entry.js | 23 + deploy/tools/feature-reporter/package.json | 22 + deploy/tools/feature-reporter/tsconfig.json | 16 + .../tools/feature-reporter/webpack.config.js | 13 + deploy/tools/feature-reporter/yarn.lock | 1069 +++++++++++++++++ deploy/values/l2-optimism-goerli/values.yaml | 2 - deploy/values/main/values.yaml | 2 - deploy/values/review-l2/values.yaml.gotmpl | 4 - deploy/values/review/values.yaml.gotmpl | 2 - docs/CONTRIBUTING.md | 2 +- docs/ENVS.md | 427 +++++-- lib/api/buildUrl.ts | 6 +- lib/api/buildUrlNode.ts | 6 +- lib/api/isNeedProxy.ts | 6 +- lib/api/resources.ts | 38 +- lib/api/useApiFetch.tsx | 4 +- lib/csp/policies/app.ts | 33 +- lib/csp/policies/googleAnalytics.ts | 4 +- lib/csp/policies/googleReCaptcha.ts | 4 +- lib/csp/policies/mixpanel.ts | 4 +- lib/csp/policies/walletConnect.ts | 4 +- lib/hooks/useHasAccount.ts | 4 +- lib/hooks/useIssueUrl.tsx | 6 +- lib/hooks/useLoginUrl.tsx | 4 +- lib/hooks/useNavItems.tsx | 27 +- lib/metadata/generate.ts | 4 +- lib/mixpanel/isGoogleAnalyticsLoaded.ts | 4 +- lib/mixpanel/logEvent.ts | 4 +- lib/mixpanel/useInit.tsx | 12 +- lib/mixpanel/useLogPageView.tsx | 4 +- lib/networks/getNetworkTitle.ts | 4 +- lib/networks/getNetworkValidatorTitle.ts | 4 +- lib/networks/networkExplorers.ts | 4 +- lib/next/getServerSideProps.ts | 18 +- lib/next/middlewares/account.ts | 12 +- lib/web3/useProvider.tsx | 8 +- lib/web3/wallets.ts | 2 +- pages/_app.tsx | 4 +- pages/_document.tsx | 6 +- pages/api/proxy.ts | 4 +- types/client/wallets.ts | 2 +- types/envs.ts | 43 +- ui/address/AddressBlocksValidated.tsx | 4 +- ui/address/AddressCsvExportLink.tsx | 4 +- .../AddressBlocksValidatedListItem.tsx | 4 +- .../coinBalance/AddressCoinBalanceChart.tsx | 6 +- .../coinBalance/AddressCoinBalanceHistory.tsx | 4 +- .../AddressCoinBalanceListItem.tsx | 4 +- .../contract/ContractMethodConstant.tsx | 4 +- .../contract/ContractMethodsAccordionItem.tsx | 2 +- ui/address/contract/ContractWrite.tsx | 6 +- ui/address/details/AddressBalance.tsx | 11 +- .../internals/AddressIntTxsListItem.tsx | 6 +- ui/address/internals/AddressIntTxsTable.tsx | 4 +- .../internals/AddressIntTxsTableItem.tsx | 4 +- ui/address/tokens/TokenBalances.tsx | 8 +- .../steps/AddressVerificationStepAddress.tsx | 4 +- .../AddressVerificationStepSignature.tsx | 4 +- ui/addresses/AddressesListItem.tsx | 6 +- ui/addresses/AddressesTable.tsx | 4 +- ui/addresses/AddressesTableItem.tsx | 4 +- ui/apiDocs/SwaggerUI.tsx | 6 +- ui/block/BlockDetails.tsx | 24 +- ui/blocks/BlocksListItem.tsx | 8 +- ui/blocks/BlocksTable.tsx | 10 +- ui/blocks/BlocksTableItem.tsx | 6 +- ui/csvExport/CsvExportFormReCaptcha.tsx | 6 +- ui/graphQL/GraphQL.tsx | 6 +- ui/home/LatestBlocks.tsx | 6 +- ui/home/LatestBlocksItem.tsx | 4 +- ui/home/LatestDepositsItem.tsx | 6 +- ui/home/LatestTxsItem.tsx | 4 +- ui/home/LatestTxsItemMobile.tsx | 6 +- ui/home/Stats.tsx | 6 +- ui/home/Transactions.tsx | 6 +- ui/home/indicators/ChainIndicators.tsx | 8 +- ui/home/indicators/utils/indicators.tsx | 11 +- ui/l2Deposits/DepositsListItem.tsx | 8 +- ui/l2Deposits/DepositsTableItem.tsx | 8 +- ui/l2OutputRoots/OutputRootsListItem.tsx | 4 +- ui/l2OutputRoots/OutputRootsTableItem.tsx | 4 +- ui/l2TxnBatches/TxnBatchesListItem.tsx | 6 +- ui/l2TxnBatches/TxnBatchesTableItem.tsx | 6 +- ui/l2Withdrawals/WithdrawalsListItem.tsx | 6 +- ui/l2Withdrawals/WithdrawalsTableItem.tsx | 6 +- ui/marketplace/useMarketplaceApps.tsx | 4 +- ui/pages/Address.tsx | 4 +- ui/pages/Block.tsx | 6 +- ui/pages/Home.tsx | 10 +- ui/pages/Login.tsx | 4 +- ui/pages/Marketplace.tsx | 6 +- ui/pages/MarketplaceApp.tsx | 18 +- ui/pages/Stats.tsx | 4 +- ui/pages/Token.tsx | 11 +- ui/pages/Transactions.tsx | 4 +- ui/pages/VerifiedAddresses.tsx | 12 +- ui/pages/Withdrawals.tsx | 5 +- ui/shared/AddressActions/Menu.tsx | 4 +- .../AddressActions/TokenInfoMenuItem.tsx | 8 +- ui/shared/AddressHeadingInfo.tsx | 6 +- .../AppError/AppErrorTooManyRequests.tsx | 6 +- ui/shared/GoogleAnalytics.tsx | 6 +- ui/shared/NetworkAddToWallet.tsx | 30 +- ui/shared/NetworkExplorers.tsx | 4 +- ui/shared/Page/PageContent.tsx | 4 +- ui/shared/TokenLogo.tsx | 2 +- ui/shared/Web3ModalProvider.tsx | 30 +- ui/shared/ad/AdBanner.tsx | 8 +- ui/shared/ad/AdbutlerBanner.tsx | 16 +- ui/shared/ad/SliseBanner.tsx | 6 +- ui/shared/ad/TextAd.tsx | 4 +- ui/shared/ad/adbutlerScript.ts | 14 +- ui/shared/address/AddressAddToWallet.tsx | 8 +- ui/snippets/footer/Footer.tsx | 34 +- ui/snippets/header/Burger.tsx | 6 +- ui/snippets/header/Header.tsx | 8 +- ui/snippets/navigation/NavigationDesktop.tsx | 6 +- ui/snippets/networkMenu/NetworkLogo.tsx | 16 +- ui/snippets/networkMenu/useNetworkMenu.tsx | 6 +- .../profileMenu/ProfileMenuContent.tsx | 4 +- ui/token/TokenVerifiedInfo.tsx | 6 +- ui/tokenInfo/TokenInfoForm.tsx | 6 +- ui/tx/TxDetails.tsx | 22 +- ui/tx/details/TxDetailsAction.tsx | 10 +- ui/tx/internals/TxInternalsListItem.tsx | 6 +- ui/tx/internals/TxInternalsTable.tsx | 6 +- ui/tx/internals/TxInternalsTableItem.tsx | 4 +- ui/tx/state/utils.tsx | 10 +- ui/txs/TxAdditionalInfoContent.tsx | 4 +- ui/txs/TxsListItem.tsx | 6 +- ui/txs/TxsTable.tsx | 6 +- .../VerifiedContractsListItem.tsx | 6 +- .../VerifiedContractsTable.tsx | 4 +- .../VerifiedContractsTableItem.tsx | 4 +- .../AddressModal/AddressFormNotifications.tsx | 4 +- .../WatchlistTable/WatchListAddressItem.tsx | 25 +- ui/withdrawals/WithdrawalsListItem.tsx | 4 +- ui/withdrawals/WithdrawalsTable.tsx | 4 +- 180 files changed, 2644 insertions(+), 1012 deletions(-) create mode 100644 configs/app/api.ts create mode 100644 configs/app/app.ts create mode 100644 configs/app/chain.ts delete mode 100644 configs/app/config.ts create mode 100644 configs/app/features/account.ts create mode 100644 configs/app/features/addressVerification.ts create mode 100644 configs/app/features/adsBanner.ts create mode 100644 configs/app/features/adsText.ts create mode 100644 configs/app/features/beaconChain.ts create mode 100644 configs/app/features/blockchainInteraction.ts create mode 100644 configs/app/features/csvExport.ts create mode 100644 configs/app/features/googleAnalytics.ts create mode 100644 configs/app/features/graphqlApiDocs.ts create mode 100644 configs/app/features/index.ts create mode 100644 configs/app/features/marketplace.ts create mode 100644 configs/app/features/mixpanel.ts create mode 100644 configs/app/features/restApiDocs.ts create mode 100644 configs/app/features/rollup.ts create mode 100644 configs/app/features/sentry.ts create mode 100644 configs/app/features/sol2uml.ts create mode 100644 configs/app/features/stats.ts create mode 100644 configs/app/features/verifiedTokens.ts create mode 100644 configs/app/features/web3Wallet.ts create mode 100644 configs/app/index.ts create mode 100644 configs/app/services.ts create mode 100644 configs/app/ui.ts create mode 100644 configs/app/utils.ts create mode 100644 deploy/tools/feature-reporter/.gitignore create mode 100755 deploy/tools/feature-reporter/dev.sh create mode 100644 deploy/tools/feature-reporter/entry.js create mode 100644 deploy/tools/feature-reporter/package.json create mode 100644 deploy/tools/feature-reporter/tsconfig.json create mode 100644 deploy/tools/feature-reporter/webpack.config.js create mode 100644 deploy/tools/feature-reporter/yarn.lock diff --git a/.eslintrc.js b/.eslintrc.js index 02bb3b864b..d194b50044 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -211,7 +211,7 @@ module.exports = { object: 'process', property: 'env', // FIXME: restrict the rule only NEXT_PUBLIC variables - message: 'Please use configs/app/config.ts to import any NEXT_PUBLIC environment variables. For other properties please disable this rule for a while.', + message: 'Please use configs/app/index.ts to import any NEXT_PUBLIC environment variables. For other properties please disable this rule for a while.', } ], 'react/jsx-key': 'error', @@ -289,7 +289,7 @@ module.exports = { }, }, { - files: [ 'configs/**/*.js', 'configs/**/*.ts', '*.config.ts', 'playwright/**/*.ts', 'deploy/tools/**/*.ts' ], + files: [ 'configs/**/*.js', 'configs/**/*.ts', '*.config.ts', 'playwright/**/*.ts', 'deploy/tools/**' ], rules: { // for configs allow to consume env variables from process.env directly 'no-restricted-properties': [ 0 ], diff --git a/Dockerfile b/Dockerfile index 0a12f674a1..44da2036aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,14 @@ COPY package.json yarn.lock ./ RUN apk add git RUN yarn --frozen-lockfile + +### FEATURE REPORTER +# Install dependencies +WORKDIR /feature-reporter +COPY ./deploy/tools/feature-reporter/package.json ./deploy/tools/feature-reporter/yarn.lock ./ +RUN yarn --frozen-lockfile + + ### ENV VARIABLES CHECKER # Install dependencies WORKDIR /envs-validator @@ -52,6 +60,13 @@ RUN ./make_envs_template.sh ./docs/ENVS.md RUN yarn build +### FEATURE REPORTER +# Copy dependencies and source code, then build +COPY --from=deps /feature-reporter/node_modules ./deploy/tools/feature-reporter/node_modules +RUN cd ./deploy/tools/feature-reporter && yarn compile_config +RUN cd ./deploy/tools/feature-reporter && yarn build + + ### ENV VARIABLES CHECKER # Copy dependencies and source code, then build WORKDIR /envs-validator @@ -81,6 +96,7 @@ COPY --from=builder /app/next.config.js ./ COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json COPY --from=builder /envs-validator/index.js ./envs-validator.js +COPY --from=builder /app/deploy/tools/feature-reporter/index.js ./feature-reporter.js # Copy scripts and ENVs file COPY --chmod=+x ./deploy/scripts/entrypoint.sh . diff --git a/configs/app/api.ts b/configs/app/api.ts new file mode 100644 index 0000000000..db87703633 --- /dev/null +++ b/configs/app/api.ts @@ -0,0 +1,23 @@ +import stripTrailingSlash from 'lib/stripTrailingSlash'; + +import { getEnvValue } from './utils'; + +const apiHost = getEnvValue(process.env.NEXT_PUBLIC_API_HOST); +const apiSchema = getEnvValue(process.env.NEXT_PUBLIC_API_PROTOCOL) || 'https'; +const apiPort = getEnvValue(process.env.NEXT_PUBLIC_API_PORT); +const apiEndpoint = [ + apiSchema || 'https', + '://', + apiHost, + apiPort && ':' + apiPort, +].filter(Boolean).join(''); +const socketSchema = getEnvValue(process.env.NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL) || 'wss'; + +const api = Object.freeze({ + host: apiHost, + endpoint: apiEndpoint, + socket: `${ socketSchema }://${ apiHost }`, + basePath: stripTrailingSlash(getEnvValue(process.env.NEXT_PUBLIC_API_BASE_PATH) || ''), +}); + +export default api; diff --git a/configs/app/app.ts b/configs/app/app.ts new file mode 100644 index 0000000000..04d8c598b0 --- /dev/null +++ b/configs/app/app.ts @@ -0,0 +1,23 @@ +import { getEnvValue } from './utils'; + +const appPort = getEnvValue(process.env.NEXT_PUBLIC_APP_PORT); +const appSchema = getEnvValue(process.env.NEXT_PUBLIC_APP_PROTOCOL); +const appHost = getEnvValue(process.env.NEXT_PUBLIC_APP_HOST); +const baseUrl = [ + appSchema || 'https', + '://', + appHost, + appPort && ':' + appPort, +].filter(Boolean).join(''); +const isDev = process.env.NODE_ENV === 'development'; + +const app = Object.freeze({ + isDev, + protocol: appSchema, + host: appHost, + port: appPort, + baseUrl, + useProxy: getEnvValue(process.env.NEXT_PUBLIC_USE_NEXT_JS_PROXY) === 'true', +}); + +export default app; diff --git a/configs/app/chain.ts b/configs/app/chain.ts new file mode 100644 index 0000000000..db088990d0 --- /dev/null +++ b/configs/app/chain.ts @@ -0,0 +1,19 @@ +import { getEnvValue } from './utils'; + +const DEFAULT_CURRENCY_DECIMALS = 18; + +const chain = Object.freeze({ + id: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ID), + name: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_NAME), + shortName: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_SHORT_NAME), + currency: { + name: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_NAME), + symbol: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL), + decimals: Number(getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS)) || DEFAULT_CURRENCY_DECIMALS, + }, + rpcUrl: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_RPC_URL), + isTestnet: getEnvValue(process.env.NEXT_PUBLIC_IS_TESTNET) === 'true', + verificationType: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE) || 'mining', +}); + +export default chain; diff --git a/configs/app/config.ts b/configs/app/config.ts deleted file mode 100644 index 6892ec07b0..0000000000 --- a/configs/app/config.ts +++ /dev/null @@ -1,213 +0,0 @@ -/* eslint-disable no-restricted-properties */ -import type { AdButlerConfig } from 'types/client/adButlerConfig'; -import type { AdBannerProviders, AdTextProviders } from 'types/client/adProviders'; -import type { NavItemExternal } from 'types/client/navigation-items'; -import type { WalletType } from 'types/client/wallets'; -import type { NetworkExplorer } from 'types/networks'; -import type { ChainIndicatorId } from 'ui/home/indicators/types'; - -import stripTrailingSlash from 'lib/stripTrailingSlash'; - -const getEnvValue = (env: T | undefined): T | undefined => env?.replaceAll('\'', '"') as T; -const parseEnvJson = (env: string | undefined): DataType | null => { - try { - return JSON.parse(env || 'null') as DataType | null; - } catch (error) { - return null; - } -}; - -const getWeb3DefaultWallet = (): WalletType => { - const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_DEFAULT_WALLET); - const SUPPORTED_WALLETS: Array = [ - 'metamask', - 'coinbase', - ]; - - return (envValue && SUPPORTED_WALLETS.includes(envValue) ? envValue : 'metamask') as WalletType; -}; - -const getAdBannerProvider = (): AdBannerProviders => { - const envValue = getEnvValue(process.env.NEXT_PUBLIC_AD_BANNER_PROVIDER); - const SUPPORTED_AD_BANNER_PROVIDERS: Array = [ 'slise', 'adbutler', 'coinzilla', 'none' ]; - - return (envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'slise') as AdBannerProviders; -}; - -const getAdTextProvider = (): AdTextProviders => { - const envValue = getEnvValue(process.env.NEXT_PUBLIC_AD_TEXT_PROVIDER); - const SUPPORTED_AD_BANNER_PROVIDERS: Array = [ 'coinzilla', 'none' ]; - - return (envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'slise') as AdTextProviders; -}; - -const env = process.env.NODE_ENV; -const isDev = env === 'development'; - -const appPort = getEnvValue(process.env.NEXT_PUBLIC_APP_PORT); -const appSchema = getEnvValue(process.env.NEXT_PUBLIC_APP_PROTOCOL); -const appHost = getEnvValue(process.env.NEXT_PUBLIC_APP_HOST); -const baseUrl = [ - appSchema || 'https', - '://', - appHost, - appPort && ':' + appPort, -].filter(Boolean).join(''); -const authUrl = getEnvValue(process.env.NEXT_PUBLIC_AUTH_URL) || baseUrl; -const apiHost = getEnvValue(process.env.NEXT_PUBLIC_API_HOST); -const apiSchema = getEnvValue(process.env.NEXT_PUBLIC_API_PROTOCOL) || 'https'; -const apiPort = getEnvValue(process.env.NEXT_PUBLIC_API_PORT); -const apiEndpoint = apiHost ? [ - apiSchema || 'https', - '://', - apiHost, - apiPort && ':' + apiPort, -].filter(Boolean).join('') : 'https://blockscout.com'; - -const socketSchema = getEnvValue(process.env.NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL) || 'wss'; - -const logoutUrl = (() => { - try { - const envUrl = getEnvValue(process.env.NEXT_PUBLIC_LOGOUT_URL); - const auth0ClientId = getEnvValue(process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID); - const returnUrl = authUrl + '/auth/logout'; - - if (!envUrl || !auth0ClientId) { - throw Error(); - } - - const url = new URL(envUrl); - url.searchParams.set('client_id', auth0ClientId); - url.searchParams.set('returnTo', returnUrl); - return url.toString(); - } catch (error) { - return; - } -})(); - -const DEFAULT_CURRENCY_DECIMALS = 18; - -const config = Object.freeze({ - env, - isDev, - network: { - logo: { - 'default': getEnvValue(process.env.NEXT_PUBLIC_NETWORK_LOGO), - dark: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_LOGO_DARK), - }, - icon: { - 'default': getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ICON), - dark: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ICON_DARK), - }, - name: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_NAME), - id: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ID), - shortName: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_SHORT_NAME), - currency: { - name: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_NAME), - symbol: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL), - decimals: Number(getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS)) || DEFAULT_CURRENCY_DECIMALS, - address: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS), - }, - explorers: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_NETWORK_EXPLORERS)) || [], - verificationType: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE) || 'mining', - rpcUrl: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_RPC_URL), - isTestnet: getEnvValue(process.env.NEXT_PUBLIC_IS_TESTNET) === 'true', - }, - navigation: { - otherLinks: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_OTHER_LINKS)) || [], - featuredNetworks: getEnvValue(process.env.NEXT_PUBLIC_FEATURED_NETWORKS), - }, - footer: { - links: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_LINKS), - frontendVersion: getEnvValue(process.env.NEXT_PUBLIC_GIT_TAG), - frontendCommit: getEnvValue(process.env.NEXT_PUBLIC_GIT_COMMIT_SHA), - }, - marketplace: { - configUrl: getEnvValue(process.env.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL), - submitForm: getEnvValue(process.env.NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM), - }, - account: { - isEnabled: getEnvValue(process.env.NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED) === 'true', - authUrl, - logoutUrl, - }, - app: { - protocol: appSchema, - host: appHost, - port: appPort, - baseUrl, - useNextJsProxy: getEnvValue(process.env.NEXT_PUBLIC_USE_NEXT_JS_PROXY) === 'true', - }, - ad: { - adBannerProvider: getAdBannerProvider(), - adTextProvider: getAdTextProvider(), - adButlerConfigDesktop: parseEnvJson(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP)), - adButlerConfigMobile: parseEnvJson(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE)), - }, - web3: { - defaultWallet: getWeb3DefaultWallet(), - disableAddTokenToWallet: getEnvValue(process.env.NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET) === 'true', - }, - api: { - host: apiHost, - endpoint: apiEndpoint, - socket: apiHost ? `${ socketSchema }://${ apiHost }` : 'wss://blockscout.com', - basePath: stripTrailingSlash(getEnvValue(process.env.NEXT_PUBLIC_API_BASE_PATH) || ''), - }, - L2: { - isL2Network: getEnvValue(process.env.NEXT_PUBLIC_IS_L2_NETWORK) === 'true', - L1BaseUrl: getEnvValue(process.env.NEXT_PUBLIC_L1_BASE_URL), - withdrawalUrl: getEnvValue(process.env.NEXT_PUBLIC_L2_WITHDRAWAL_URL) || '', - }, - beaconChain: { - hasBeaconChain: getEnvValue(process.env.NEXT_PUBLIC_HAS_BEACON_CHAIN) === 'true', - currencySymbol: getEnvValue(process.env.NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL) || getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL), - }, - statsApi: { - endpoint: getEnvValue(process.env.NEXT_PUBLIC_STATS_API_HOST), - basePath: '', - }, - visualizeApi: { - endpoint: getEnvValue(process.env.NEXT_PUBLIC_VISUALIZE_API_HOST), - basePath: '', - }, - contractInfoApi: { - endpoint: getEnvValue(process.env.NEXT_PUBLIC_CONTRACT_INFO_API_HOST), - basePath: '', - }, - adminServiceApi: { - endpoint: getEnvValue(process.env.NEXT_PUBLIC_ADMIN_SERVICE_API_HOST), - basePath: '', - }, - homepage: { - charts: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_CHARTS)) || [], - plate: { - background: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND) || - 'radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)', - textColor: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR) || 'white', - }, - showGasTracker: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER) === 'false' ? false : true, - showAvgBlockTime: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME) === 'false' ? false : true, - }, - walletConnect: { - projectId: getEnvValue(process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID), - }, - apiDoc: { - specUrl: getEnvValue(process.env.NEXT_PUBLIC_API_SPEC_URL), - }, - reCaptcha: { - siteKey: getEnvValue(process.env.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY) || '', - }, - googleAnalytics: { - propertyId: getEnvValue(process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID), - }, - mixpanel: { - projectToken: getEnvValue(process.env.NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN), - }, - graphQL: { - defaultTxnHash: getEnvValue(process.env.NEXT_PUBLIC_GRAPHIQL_TRANSACTION) || '', - }, - hideIndexingAlert: getEnvValue(process.env.NEXT_PUBLIC_HIDE_INDEXING_ALERT), -}); - -export default config; diff --git a/configs/app/features/account.ts b/configs/app/features/account.ts new file mode 100644 index 0000000000..43c29659ce --- /dev/null +++ b/configs/app/features/account.ts @@ -0,0 +1,33 @@ +import stripTrailingSlash from 'lib/stripTrailingSlash'; + +import app from '../app'; +import { getEnvValue } from '../utils'; + +const authUrl = stripTrailingSlash(getEnvValue(process.env.NEXT_PUBLIC_AUTH_URL) || app.baseUrl); + +const logoutUrl = (() => { + try { + const envUrl = getEnvValue(process.env.NEXT_PUBLIC_LOGOUT_URL); + const auth0ClientId = getEnvValue(process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID); + const returnUrl = authUrl + '/auth/logout'; + + if (!envUrl || !auth0ClientId) { + throw Error(); + } + + const url = new URL(envUrl); + url.searchParams.set('client_id', auth0ClientId); + url.searchParams.set('returnTo', returnUrl); + + return url.toString(); + } catch (error) { + return; + } +})(); + +export default Object.freeze({ + title: 'My account', + isEnabled: getEnvValue(process.env.NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED) === 'true', + authUrl, + logoutUrl, +}); diff --git a/configs/app/features/addressVerification.ts b/configs/app/features/addressVerification.ts new file mode 100644 index 0000000000..567e72628f --- /dev/null +++ b/configs/app/features/addressVerification.ts @@ -0,0 +1,14 @@ +import { getEnvValue } from '../utils'; +import account from './account'; +import verifiedTokens from './verifiedTokens'; + +const adminServiceApiHost = getEnvValue(process.env.NEXT_PUBLIC_ADMIN_SERVICE_API_HOST); + +export default Object.freeze({ + title: 'Address verification in "My account"', + isEnabled: account.isEnabled && verifiedTokens.isEnabled && Boolean(adminServiceApiHost), + api: { + endpoint: adminServiceApiHost, + basePath: '', + }, +}); diff --git a/configs/app/features/adsBanner.ts b/configs/app/features/adsBanner.ts new file mode 100644 index 0000000000..01415608b6 --- /dev/null +++ b/configs/app/features/adsBanner.ts @@ -0,0 +1,23 @@ +import type { AdButlerConfig } from 'types/client/adButlerConfig'; +import type { AdBannerProviders } from 'types/client/adProviders'; + +import { getEnvValue, parseEnvJson } from '../utils'; + +const provider: AdBannerProviders = (() => { + const envValue = getEnvValue(process.env.NEXT_PUBLIC_AD_BANNER_PROVIDER) as AdBannerProviders; + const SUPPORTED_AD_BANNER_PROVIDERS: Array = [ 'slise', 'adbutler', 'coinzilla', 'none' ]; + + return envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'slise'; +})(); + +export default Object.freeze({ + title: 'Banner ads', + isEnabled: provider !== 'none', + provider, + adButler: { + config: { + desktop: parseEnvJson(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP)) ?? undefined, + mobile: parseEnvJson(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE)) ?? undefined, + }, + }, +}); diff --git a/configs/app/features/adsText.ts b/configs/app/features/adsText.ts new file mode 100644 index 0000000000..817e7db687 --- /dev/null +++ b/configs/app/features/adsText.ts @@ -0,0 +1,16 @@ +import type { AdTextProviders } from 'types/client/adProviders'; + +import { getEnvValue } from '../utils'; + +const provider: AdTextProviders = (() => { + const envValue = getEnvValue(process.env.NEXT_PUBLIC_AD_TEXT_PROVIDER); + const SUPPORTED_AD_BANNER_PROVIDERS = [ 'coinzilla', 'none' ]; + + return envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue as AdTextProviders : 'coinzilla'; +})(); + +export default Object.freeze({ + title: 'Text ads', + isEnabled: provider !== 'none', + provider, +}); diff --git a/configs/app/features/beaconChain.ts b/configs/app/features/beaconChain.ts new file mode 100644 index 0000000000..40c36123b1 --- /dev/null +++ b/configs/app/features/beaconChain.ts @@ -0,0 +1,9 @@ +import { getEnvValue } from '../utils'; + +export default Object.freeze({ + title: 'Beacon chain', + isEnabled: getEnvValue(process.env.NEXT_PUBLIC_HAS_BEACON_CHAIN) === 'true', + currency: { + symbol: getEnvValue(process.env.NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL) || getEnvValue(process.env.NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL), + }, +}); diff --git a/configs/app/features/blockchainInteraction.ts b/configs/app/features/blockchainInteraction.ts new file mode 100644 index 0000000000..a6584ca417 --- /dev/null +++ b/configs/app/features/blockchainInteraction.ts @@ -0,0 +1,22 @@ +import chain from '../chain'; +import { getEnvValue } from '../utils'; + +const walletConnectProjectId = getEnvValue(process.env.NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID); + +export default Object.freeze({ + title: 'Blockchain interaction (writing to contract, etc.)', + isEnabled: Boolean( + // all chain parameters are required for wagmi provider + // @wagmi/chains/dist/index.d.ts + chain.id && + chain.name && + chain.currency.name && + chain.currency.symbol && + chain.currency.decimals && + chain.rpcUrl && + walletConnectProjectId, + ), + walletConnect: { + projectId: walletConnectProjectId ?? '', + }, +}); diff --git a/configs/app/features/csvExport.ts b/configs/app/features/csvExport.ts new file mode 100644 index 0000000000..d106fd52b0 --- /dev/null +++ b/configs/app/features/csvExport.ts @@ -0,0 +1,11 @@ +import { getEnvValue } from '../utils'; + +const reCaptchaSiteKey = getEnvValue(process.env.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY); + +export default Object.freeze({ + title: 'Export data to CSV file', + isEnabled: Boolean(reCaptchaSiteKey), + reCaptcha: { + siteKey: reCaptchaSiteKey ?? '', + }, +}); diff --git a/configs/app/features/googleAnalytics.ts b/configs/app/features/googleAnalytics.ts new file mode 100644 index 0000000000..686d605fc2 --- /dev/null +++ b/configs/app/features/googleAnalytics.ts @@ -0,0 +1,9 @@ +import { getEnvValue } from '../utils'; + +const propertyId = getEnvValue(process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID); + +export default Object.freeze({ + title: 'Google analytics', + isEnabled: Boolean(propertyId), + propertyId, +}); diff --git a/configs/app/features/graphqlApiDocs.ts b/configs/app/features/graphqlApiDocs.ts new file mode 100644 index 0000000000..d92e3988fc --- /dev/null +++ b/configs/app/features/graphqlApiDocs.ts @@ -0,0 +1,9 @@ +import { getEnvValue } from '../utils'; + +const defaultTxHash = getEnvValue(process.env.NEXT_PUBLIC_GRAPHIQL_TRANSACTION); + +export default Object.freeze({ + title: 'GraphQL API documentation', + isEnabled: true, + defaultTxHash, +}); diff --git a/configs/app/features/index.ts b/configs/app/features/index.ts new file mode 100644 index 0000000000..cc4df93cd4 --- /dev/null +++ b/configs/app/features/index.ts @@ -0,0 +1,18 @@ +export { default as account } from './account'; +export { default as addressVerification } from './addressVerification'; +export { default as adsBanner } from './adsBanner'; +export { default as adsText } from './adsText'; +export { default as beaconChain } from './beaconChain'; +export { default as blockchainInteraction } from './blockchainInteraction'; +export { default as csvExport } from './csvExport'; +export { default as googleAnalytics } from './googleAnalytics'; +export { default as graphqlApiDocs } from './graphqlApiDocs'; +export { default as marketplace } from './marketplace'; +export { default as mixpanel } from './mixpanel'; +export { default as restApiDocs } from './restApiDocs'; +export { default as rollup } from './rollup'; +export { default as sentry } from './sentry'; +export { default as sol2uml } from './sol2uml'; +export { default as stats } from './stats'; +export { default as web3Wallet } from './web3Wallet'; +export { default as verifiedTokens } from './verifiedTokens'; diff --git a/configs/app/features/marketplace.ts b/configs/app/features/marketplace.ts new file mode 100644 index 0000000000..fe1669127e --- /dev/null +++ b/configs/app/features/marketplace.ts @@ -0,0 +1,12 @@ +import chain from '../chain'; +import { getEnvValue } from '../utils'; + +const configUrl = getEnvValue(process.env.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL); +const submitForm = getEnvValue(process.env.NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM); + +export default Object.freeze({ + title: 'Marketplace', + isEnabled: Boolean(chain.rpcUrl && configUrl && submitForm), + configUrl: configUrl ?? '', + submitFormUrl: submitForm ?? '', +}); diff --git a/configs/app/features/mixpanel.ts b/configs/app/features/mixpanel.ts new file mode 100644 index 0000000000..402ac2abac --- /dev/null +++ b/configs/app/features/mixpanel.ts @@ -0,0 +1,9 @@ +import { getEnvValue } from '../utils'; + +const projectToken = getEnvValue(process.env.NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN); + +export default Object.freeze({ + title: 'Mixpanel analytics', + isEnabled: Boolean(projectToken), + projectToken: projectToken ?? '', +}); diff --git a/configs/app/features/restApiDocs.ts b/configs/app/features/restApiDocs.ts new file mode 100644 index 0000000000..0bf939e1d0 --- /dev/null +++ b/configs/app/features/restApiDocs.ts @@ -0,0 +1,9 @@ +import { getEnvValue } from '../utils'; + +const specUrl = getEnvValue(process.env.NEXT_PUBLIC_API_SPEC_URL); + +export default Object.freeze({ + title: 'REST API documentation', + isEnabled: Boolean(specUrl), + specUrl, +}); diff --git a/configs/app/features/rollup.ts b/configs/app/features/rollup.ts new file mode 100644 index 0000000000..2324bd8467 --- /dev/null +++ b/configs/app/features/rollup.ts @@ -0,0 +1,8 @@ +import { getEnvValue } from '../utils'; + +export default Object.freeze({ + title: 'Rollup (L2) chain', + isEnabled: getEnvValue(process.env.NEXT_PUBLIC_IS_L2_NETWORK) === 'true', + L1BaseUrl: getEnvValue(process.env.NEXT_PUBLIC_L1_BASE_URL) ?? '', + withdrawalUrl: getEnvValue(process.env.NEXT_PUBLIC_L2_WITHDRAWAL_URL) ?? '', +}); diff --git a/configs/app/features/sentry.ts b/configs/app/features/sentry.ts new file mode 100644 index 0000000000..75afdc8227 --- /dev/null +++ b/configs/app/features/sentry.ts @@ -0,0 +1,13 @@ +import { getEnvValue } from '../utils'; + +const dsn = getEnvValue(process.env.NEXT_PUBLIC_SENTRY_DSN); + +// TODO @tom2drum check sentry setup +export default Object.freeze({ + title: 'Sentry error monitoring', + isEnabled: Boolean(dsn), + dsn, + environment: getEnvValue(process.env.NEXT_PUBLIC_APP_ENV) || getEnvValue(process.env.NODE_ENV), + cspReportUrl: getEnvValue(process.env.SENTRY_CSP_REPORT_URI), + instance: getEnvValue(process.env.NEXT_PUBLIC_APP_INSTANCE), +}); diff --git a/configs/app/features/sol2uml.ts b/configs/app/features/sol2uml.ts new file mode 100644 index 0000000000..bfff07dcc9 --- /dev/null +++ b/configs/app/features/sol2uml.ts @@ -0,0 +1,12 @@ +import { getEnvValue } from '../utils'; + +const apiEndpoint = getEnvValue(process.env.NEXT_PUBLIC_VISUALIZE_API_HOST); + +export default Object.freeze({ + title: 'Solidity to UML diagrams', + isEnabled: Boolean(apiEndpoint), + api: { + endpoint: apiEndpoint, + basePath: '', + }, +}); diff --git a/configs/app/features/stats.ts b/configs/app/features/stats.ts new file mode 100644 index 0000000000..b698b5fb8c --- /dev/null +++ b/configs/app/features/stats.ts @@ -0,0 +1,12 @@ +import { getEnvValue } from '../utils'; + +const apiEndpoint = getEnvValue(process.env.NEXT_PUBLIC_STATS_API_HOST); + +export default Object.freeze({ + title: 'Blockchain statistics', + isEnabled: Boolean(apiEndpoint), + api: { + endpoint: apiEndpoint, + basePath: '', + }, +}); diff --git a/configs/app/features/verifiedTokens.ts b/configs/app/features/verifiedTokens.ts new file mode 100644 index 0000000000..7f58a82e60 --- /dev/null +++ b/configs/app/features/verifiedTokens.ts @@ -0,0 +1,12 @@ +import { getEnvValue } from '../utils'; + +const contractInfoApiHost = getEnvValue(process.env.NEXT_PUBLIC_CONTRACT_INFO_API_HOST); + +export default Object.freeze({ + title: 'Verified tokens info', + isEnabled: Boolean(contractInfoApiHost), + api: { + endpoint: contractInfoApiHost, + basePath: '', + }, +}); diff --git a/configs/app/features/web3Wallet.ts b/configs/app/features/web3Wallet.ts new file mode 100644 index 0000000000..5501ecd320 --- /dev/null +++ b/configs/app/features/web3Wallet.ts @@ -0,0 +1,23 @@ +import type { WalletType } from 'types/client/wallets'; + +import { getEnvValue } from '../utils'; + +const defaultWallet = ((): WalletType => { + const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_DEFAULT_WALLET) as WalletType; + const SUPPORTED_WALLETS: Array = [ + 'metamask', + 'coinbase', + ]; + + return envValue && SUPPORTED_WALLETS.includes(envValue) ? envValue : 'metamask'; +})(); + +export default Object.freeze({ + title: 'Web3 wallet integration (add token or network to the wallet)', + isEnabled: defaultWallet !== 'none', + defaultWallet, + addToken: { + isDisabled: getEnvValue(process.env.NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET) === 'true', + }, + addNetwork: {}, +}); diff --git a/configs/app/index.ts b/configs/app/index.ts new file mode 100644 index 0000000000..f2253ee8fe --- /dev/null +++ b/configs/app/index.ts @@ -0,0 +1,17 @@ +import api from './api'; +import app from './app'; +import chain from './chain'; +import * as features from './features'; +import services from './services'; +import UI from './ui'; + +const config = Object.freeze({ + app, + chain, + api, + UI, + features, + services, +}); + +export default config; diff --git a/configs/app/services.ts b/configs/app/services.ts new file mode 100644 index 0000000000..a6249f611f --- /dev/null +++ b/configs/app/services.ts @@ -0,0 +1,7 @@ +import { getEnvValue } from './utils'; + +export default Object.freeze({ + reCaptcha: { + siteKey: getEnvValue(process.env.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY), + }, +}); diff --git a/configs/app/ui.ts b/configs/app/ui.ts new file mode 100644 index 0000000000..d3ddee2f93 --- /dev/null +++ b/configs/app/ui.ts @@ -0,0 +1,45 @@ +import type { NavItemExternal } from 'types/client/navigation-items'; +import type { NetworkExplorer } from 'types/networks'; +import type { ChainIndicatorId } from 'ui/home/indicators/types'; + +import { getEnvValue, parseEnvJson } from './utils'; + +// eslint-disable-next-line max-len +const HOMEPAGE_PLATE_BACKGROUND_DEFAULT = 'radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)'; + +const UI = Object.freeze({ + sidebar: { + logo: { + 'default': getEnvValue(process.env.NEXT_PUBLIC_NETWORK_LOGO), + dark: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_LOGO_DARK), + }, + icon: { + 'default': getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ICON), + dark: getEnvValue(process.env.NEXT_PUBLIC_NETWORK_ICON_DARK), + }, + otherLinks: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_OTHER_LINKS)) || [], + featuredNetworks: getEnvValue(process.env.NEXT_PUBLIC_FEATURED_NETWORKS), + }, + footer: { + links: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_LINKS), + frontendVersion: getEnvValue(process.env.NEXT_PUBLIC_GIT_TAG), + frontendCommit: getEnvValue(process.env.NEXT_PUBLIC_GIT_COMMIT_SHA), + }, + homepage: { + charts: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_CHARTS)) || [], + plate: { + background: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND) || HOMEPAGE_PLATE_BACKGROUND_DEFAULT, + textColor: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR) || 'white', + }, + showGasTracker: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER) === 'false' ? false : true, + showAvgBlockTime: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME) === 'false' ? false : true, + }, + indexingAlert: { + isHidden: getEnvValue(process.env.NEXT_PUBLIC_HIDE_INDEXING_ALERT), + }, + explorers: { + items: parseEnvJson>(getEnvValue(process.env.NEXT_PUBLIC_NETWORK_EXPLORERS)) || [], + }, +}); + +export default UI; diff --git a/configs/app/utils.ts b/configs/app/utils.ts new file mode 100644 index 0000000000..7a07b9cd0b --- /dev/null +++ b/configs/app/utils.ts @@ -0,0 +1,9 @@ +export const getEnvValue = (env: T | undefined): T | undefined => env?.replaceAll('\'', '"') as T; + +export const parseEnvJson = (env: string | undefined): DataType | null => { + try { + return JSON.parse(env || 'null') as DataType | null; + } catch (error) { + return null; + } +}; diff --git a/configs/envs/.env.eth b/configs/envs/.env.eth index 4f312012f8..ddf01df54f 100644 --- a/configs/envs/.env.eth +++ b/configs/envs/.env.eth @@ -1,41 +1,43 @@ # Set of ENVs for Ethereum network explorer # https://eth.blockscout.com/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development - -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth.json -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Etherscan','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] -NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=Ethereum NEXT_PUBLIC_NETWORK_SHORT_NAME=ETH -NEXT_PUBLIC_NETWORK_LOGO= -NEXT_PUBLIC_NETWORK_ICON= NEXT_PUBLIC_NETWORK_ID=1 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS= -NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_NETWORK_RPC_URL=https://eth.llamarpc.com -NEXT_PUBLIC_MARKETPLACE_CONFIG_URL= -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs', 'coin_price', 'market_cap'] -NEXT_PUBLIC_IS_TESTNET=false -NEXT_PUBLIC_HAS_BEACON_CHAIN=true -# api config +# api configuration NEXT_PUBLIC_API_HOST=eth.blockscout.com NEXT_PUBLIC_API_BASE_PATH=/ + +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs', 'coin_price', 'market_cap'] +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth.json +## footer +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Etherscan','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_HAS_BEACON_CHAIN=true +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com diff --git a/configs/envs/.env.eth_goerli b/configs/envs/.env.eth_goerli index 7bcb6e0269..bcc5422718 100644 --- a/configs/envs/.env.eth_goerli +++ b/configs/envs/.env.eth_goerli @@ -1,42 +1,47 @@ # Set of ENVs for Goerli testnet network explorer # https://eth-goerli.blockscout.com/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] -NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml - -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=Goerli NEXT_PUBLIC_NETWORK_SHORT_NAME=Goerli -NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg -NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg NEXT_PUBLIC_NETWORK_ID=5 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 -NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true -NEXT_PUBLIC_AUTH_URL=http://localhost:3000 -NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli -NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] NEXT_PUBLIC_IS_TESTNET=true -# api config +# api configuration NEXT_PUBLIC_API_HOST=eth-goerli.blockscout.com NEXT_PUBLIC_API_BASE_PATH=/ + +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json +NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg +NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg +## footer +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout +NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json +NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com diff --git a/configs/envs/.env.jest b/configs/envs/.env.jest index 7b4eb659d8..a9d41a0ef3 100644 --- a/configs/envs/.env.jest +++ b/configs/envs/.env.jest @@ -1,47 +1,52 @@ # Set of ENVs for Jest unit tests -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=jest -NEXT_PUBLIC_APP_ENV=testing + +# blockchain parameters +NEXT_PUBLIC_NETWORK_NAME=Blockscout +NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout +NEXT_PUBLIC_NETWORK_ID=1 +NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether +NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH +NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 +NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation +NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 +NEXT_PUBLIC_IS_TESTNET=true + +# api configuration +NEXT_PUBLIC_API_HOST=localhost +NEXT_PUBLIC_API_PORT=3003 +NEXT_PUBLIC_API_BASE_PATH=/ # ui config -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] -NEXT_PUBLIC_GIT_TAG=v1.0.11 +## homepage NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND= -NEXT_PUBLIC_FEATURED_NETWORKS= -NEXT_PUBLIC_FOOTER_LINKS= +## sidebar NEXT_PUBLIC_NETWORK_LOGO= NEXT_PUBLIC_NETWORK_LOGO_DARK= NEXT_PUBLIC_NETWORK_ICON= NEXT_PUBLIC_NETWORK_ICON_DARK= -NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 -NEXT_PUBLIC_IS_TESTNET=true +NEXT_PUBLIC_FEATURED_NETWORKS= +## footer +NEXT_PUBLIC_FOOTER_LINKS= +NEXT_PUBLIC_GIT_TAG=v1.0.11 +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=jest +NEXT_PUBLIC_APP_ENV=testing NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json +NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form NEXT_PUBLIC_IS_L2_NETWORK=false - -# network config -NEXT_PUBLIC_NETWORK_NAME=Blockscout -NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout -NEXT_PUBLIC_NETWORK_ID=1 -NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether -NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH -NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS= NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true -NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form - -# api config -NEXT_PUBLIC_API_HOST=localhost -NEXT_PUBLIC_API_PORT=3003 NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004 NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005 NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006 NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx -NEXT_PUBLIC_API_BASE_PATH=/ diff --git a/configs/envs/.env.localhost b/configs/envs/.env.localhost index 28af95b894..3097fff5a6 100644 --- a/configs/envs/.env.localhost +++ b/configs/envs/.env.localhost @@ -2,34 +2,40 @@ # frontend app URL - https://localhost:3000/ # API URL - https://localhost:3001/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development - -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}] -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=POA NEXT_PUBLIC_NETWORK_SHORT_NAME=POA NEXT_PUBLIC_NETWORK_ID=99 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0x029a799563238d0e75e20be2f4bda0ea68d00172 -NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network -# api config +# api configuration NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_HOST=localhost NEXT_PUBLIC_API_PROTOCOL=http -NEXT_PUBLIC_API_PORT=3001 \ No newline at end of file +NEXT_PUBLIC_API_PORT=3001 + +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json +## footer +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout diff --git a/configs/envs/.env.main b/configs/envs/.env.main index 50fd0dff73..2eaab1e09b 100644 --- a/configs/envs/.env.main +++ b/configs/envs/.env.main @@ -1,43 +1,48 @@ # Set of ENVs for Develompent network explorer # https://blockscout-main.k8s-dev.blockscout.com/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] -NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml - -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=Goerli NEXT_PUBLIC_NETWORK_SHORT_NAME=Goerli -NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg -NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg NEXT_PUBLIC_NETWORK_ID=5 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 -NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true -NEXT_PUBLIC_AUTH_URL=http://localhost:3000 -NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout -NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli -NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_IS_TESTNET=true -# api config +# api configuration NEXT_PUBLIC_API_HOST=blockscout-main.k8s-dev.blockscout.com NEXT_PUBLIC_API_BASE_PATH=/ + +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json +NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg +NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg +## footer +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout +NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json +NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.k8s-dev.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com -NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com \ No newline at end of file +NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com diff --git a/configs/envs/.env.main.L2 b/configs/envs/.env.main.L2 index 583a1d0f40..93a6ca5afb 100644 --- a/configs/envs/.env.main.L2 +++ b/configs/envs/.env.main.L2 @@ -1,46 +1,50 @@ # Set of ENVs for Develompent L2 network explorer # https://blockscout-optimism-goerli.k8s-dev.blockscout.com/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/base-goerli.json -NEXT_PUBLIC_NETWORK_EXPLORERS= -NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%) -NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 -NEXT_PUBLIC_WEB3_DEFAULT_WALLET=coinbase -NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml - -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=Base Göerli NEXT_PUBLIC_NETWORK_SHORT_NAME=Base -NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/base.svg -NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/base.svg NEXT_PUBLIC_NETWORK_ID=84531 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS= -NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_NETWORK_RPC_URL=https://goerli.base.org -NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] NEXT_PUBLIC_IS_TESTNET=true -# api config +# api configuration NEXT_PUBLIC_API_HOST=blockscout-optimism-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_API_BASE_PATH=/ -NEXT_PUBLIC_STATS_API_HOST=https://stats-optimism-goerli.k8s-dev.blockscout.com -# l2 config +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%) +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/base-goerli.json +NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/base.svg +NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/base.svg +## footer +## misc + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_WEB3_DEFAULT_WALLET=coinbase +NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout +NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json +NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C +NEXT_PUBLIC_STATS_API_HOST=https://stats-optimism-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_IS_L2_NETWORK=true NEXT_PUBLIC_L1_BASE_URL=https://blockscout-main.k8s-dev.blockscout.com -NEXT_PUBLIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw \ No newline at end of file +NEXT_PUBLIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw diff --git a/configs/envs/.env.poa_core b/configs/envs/.env.poa_core index 14c22bbe30..d798856d95 100644 --- a/configs/envs/.env.poa_core +++ b/configs/envs/.env.poa_core @@ -1,36 +1,42 @@ # Set of ENVs for POA network explorer # https://blockscout.com/poa/core/ -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3000 -NEXT_PUBLIC_APP_INSTANCE=local -NEXT_PUBLIC_APP_ENV=development -# ui config -NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address','block':'/ethereum/poa/core/block'}}] -NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] -#NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='no-repeat bottom 20% right 0px/100% url(https://neon-labs.org/images/index/banner.jpg)' -#NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=\#DCFE76 -NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/poa.svg -NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/poa.svg -NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml - -# network config +# blockchain parameters NEXT_PUBLIC_NETWORK_NAME=POA NEXT_PUBLIC_NETWORK_SHORT_NAME=POA NEXT_PUBLIC_NETWORK_ID=99 NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0x029a799563238d0e75e20be2f4bda0ea68d00172 -#NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true -NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation -NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network -#NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C -# api config +# api configuration NEXT_PUBLIC_API_HOST=blockscout.com NEXT_PUBLIC_API_BASE_PATH=/poa/core + +# ui config +## homepage +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] +NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='no-repeat bottom 20% right 0px/100% url(https://neon-labs.org/images/index/banner.jpg)' +NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=\#DCFE76 +## sidebar +NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json +NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/poa.svg +NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/poa.svg +## footer +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address','block':'/ethereum/poa/core/block'}}] + +# app features +NEXT_PUBLIC_APP_INSTANCE=local +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true +NEXT_PUBLIC_AUTH_URL=http://localhost:3000 +NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout +NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation +NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network diff --git a/configs/envs/.env.pw b/configs/envs/.env.pw index 2f466a3573..7ab26d773c 100644 --- a/configs/envs/.env.pw +++ b/configs/envs/.env.pw @@ -1,48 +1,53 @@ # Set of ENVs for Playwright components tests -# app config +# app configuration NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_PORT=3100 -NEXT_PUBLIC_APP_INSTANCE=pw -NEXT_PUBLIC_APP_ENV=testing + +# blockchain parameters +NEXT_PUBLIC_NETWORK_NAME=Blockscout +NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout +NEXT_PUBLIC_NETWORK_ID=1 +NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether +NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH +NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 +NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 +NEXT_PUBLIC_IS_TESTNET=true +NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation + +# api configuration +NEXT_PUBLIC_API_HOST=localhost +NEXT_PUBLIC_API_PORT=3003 +NEXT_PUBLIC_API_BASE_PATH=/ # ui config -NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] -NEXT_PUBLIC_GIT_TAG=v1.0.11 +## homepage NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND= +## sidebar NEXT_PUBLIC_FEATURED_NETWORKS= -NEXT_PUBLIC_FOOTER_LINKS= NEXT_PUBLIC_NETWORK_LOGO= NEXT_PUBLIC_NETWORK_LOGO_DARK= NEXT_PUBLIC_NETWORK_ICON= NEXT_PUBLIC_NETWORK_ICON_DARK= -NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 -NEXT_PUBLIC_IS_TESTNET=true +## footer +NEXT_PUBLIC_GIT_TAG=v1.0.11 +NEXT_PUBLIC_FOOTER_LINKS= +## misc +NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}] + +# app features +NEXT_PUBLIC_APP_ENV=testing +NEXT_PUBLIC_APP_INSTANCE=pw NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json +NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form NEXT_PUBLIC_IS_L2_NETWORK=false NEXT_PUBLIC_AD_BANNER_PROVIDER=slise - -# network config -NEXT_PUBLIC_NETWORK_NAME=Blockscout -NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout -NEXT_PUBLIC_NETWORK_ID=1 -NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether -NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH -NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 -NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS= NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true -NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation -NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form - -# api config -NEXT_PUBLIC_API_HOST=localhost -NEXT_PUBLIC_API_PORT=3003 NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004 NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005 NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006 NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx -NEXT_PUBLIC_API_BASE_PATH=/ diff --git a/configs/sentry/react.ts b/configs/sentry/react.ts index c760edf7d8..145a20f643 100644 --- a/configs/sentry/react.ts +++ b/configs/sentry/react.ts @@ -1,10 +1,12 @@ import type * as Sentry from '@sentry/react'; import { BrowserTracing } from '@sentry/tracing'; +import appConfig from 'configs/app'; + export const config: Sentry.BrowserOptions = { - environment: process.env.NEXT_PUBLIC_APP_ENV || process.env.NODE_ENV, - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, - release: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA, + environment: appConfig.features.sentry.environment, + dsn: appConfig.features.sentry.dsn, + release: process.env.NEXT_PUBLIC_GIT_TAG || process.env.NEXT_PUBLIC_GIT_COMMIT_SHA, integrations: [ new BrowserTracing() ], // We recommend adjusting this value in production, or using tracesSampler // for finer control @@ -55,5 +57,5 @@ export const config: Sentry.BrowserOptions = { }; export function configureScope(scope: Sentry.Scope) { - scope.setTag('app_instance', process.env.NEXT_PUBLIC_APP_INSTANCE); + scope.setTag('app_instance', appConfig.features.sentry.instance); } diff --git a/deploy/scripts/entrypoint.sh b/deploy/scripts/entrypoint.sh index b3bc3fa145..7ba02e4f9a 100755 --- a/deploy/scripts/entrypoint.sh +++ b/deploy/scripts/entrypoint.sh @@ -9,5 +9,8 @@ fi # Execute script for replace build-time ENVs placeholders with their values at runtime ./replace_envs.sh -echo "starting Nextjs" +# Print list of enabled features +node ./feature-reporter.js + +echo "Starting Next.js application" exec "$@" \ No newline at end of file diff --git a/deploy/tools/envs-validator/index.ts b/deploy/tools/envs-validator/index.ts index 5ceaed3b09..42af0c4e28 100644 --- a/deploy/tools/envs-validator/index.ts +++ b/deploy/tools/envs-validator/index.ts @@ -64,11 +64,13 @@ async function checkPlaceholdersCongruity(runTimeEnvs: Record) { } if (inconsistencies.length > 0) { - console.log(`🚸 For the following environment variables placeholders were not generated at build-time:`); + console.log('🚸 For the following environment variables placeholders were not generated at build-time:'); inconsistencies.forEach((env) => { - console.log(` ${ env }`); + console.log(` ${ env }`); }); - console.log('They are either deprecated or running the app with them may lead to unexpected behavior. Please check the documentation for more details.'); + console.log(` They are either deprecated or running the app with them may lead to unexpected behavior. + Please check the documentation for more details - https://github.com/blockscout/frontend/blob/main/docs/ENVS.md + `); throw new Error(); } diff --git a/deploy/tools/feature-reporter/.gitignore b/deploy/tools/feature-reporter/.gitignore new file mode 100644 index 0000000000..cefc90f67f --- /dev/null +++ b/deploy/tools/feature-reporter/.gitignore @@ -0,0 +1,3 @@ +/node_modules +/build +index.js \ No newline at end of file diff --git a/deploy/tools/feature-reporter/dev.sh b/deploy/tools/feature-reporter/dev.sh new file mode 100755 index 0000000000..183698a810 --- /dev/null +++ b/deploy/tools/feature-reporter/dev.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +rm -rf ./build +yarn compile_config +yarn build +dotenv -e ../../../configs/envs/.env.main -e ../../../configs/envs/.env.secrets yarn print_report \ No newline at end of file diff --git a/deploy/tools/feature-reporter/entry.js b/deploy/tools/feature-reporter/entry.js new file mode 100644 index 0000000000..01a2989035 --- /dev/null +++ b/deploy/tools/feature-reporter/entry.js @@ -0,0 +1,23 @@ +/* eslint-disable no-console */ +const config = require('./build/configs/app').default; + +run(); + +async function run() { + console.log(); + try { + console.log(`đź“‹ Here is the list of the features enabled for the running instance. +To adjust their configuration, please refer to the documentation - https://github.com/blockscout/frontend/blob/main/docs/ENVS.md#app-features + `); + Object.entries(config.features) + .forEach(([ , feature ]) => { + const mark = feature.isEnabled ? 'v' : ' '; + console.log(` [${ mark }] ${ feature.title }`); + }); + + } catch (error) { + console.log('🚨 An error occurred while generating the feature report.'); + process.exit(1); + } + console.log(); +} diff --git a/deploy/tools/feature-reporter/package.json b/deploy/tools/feature-reporter/package.json new file mode 100644 index 0000000000..1368868318 --- /dev/null +++ b/deploy/tools/feature-reporter/package.json @@ -0,0 +1,22 @@ +{ + "name": "feature-reporter", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "compile_config": "yarn tsc -p ./tsconfig.json && yarn tsc-alias -p ./tsconfig.json", + "build": "yarn webpack-cli -c ./webpack.config.js", + "print_report": "node ./index.js", + "dev": "./dev.sh" + }, + "dependencies": { + "tsc": "^2.0.4", + "tsc-alias": "^1.8.7", + "typescript": "5.1", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4" + }, + "devDependencies": { + "dotenv-cli": "^7.2.1" + } +} diff --git a/deploy/tools/feature-reporter/tsconfig.json b/deploy/tools/feature-reporter/tsconfig.json new file mode 100644 index 0000000000..4d424a20ce --- /dev/null +++ b/deploy/tools/feature-reporter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "noEmit": false, + "module": "CommonJS", + "outDir": "./build", + "paths": { + "nextjs-routes": ["./types/nextjs-routes.d.ts"], + } + }, + "include": [ "../../../configs/app/index.ts" ], + "tsc-alias": { + "verbose": true, + "resolveFullPaths": true, + } +} diff --git a/deploy/tools/feature-reporter/webpack.config.js b/deploy/tools/feature-reporter/webpack.config.js new file mode 100644 index 0000000000..41363dfeef --- /dev/null +++ b/deploy/tools/feature-reporter/webpack.config.js @@ -0,0 +1,13 @@ +const path = require('path'); +module.exports = { + mode: 'production', + target: 'node', + entry: path.resolve(__dirname, '/entry.js'), + resolve: { + extensions: [ '.js' ], + }, + output: { + filename: 'index.js', + path: path.resolve(__dirname), + }, +}; diff --git a/deploy/tools/feature-reporter/yarn.lock b/deploy/tools/feature-reporter/yarn.lock new file mode 100644 index 0000000000..eaf396937e --- /dev/null +++ b/deploy/tools/feature-reporter/yarn.lock @@ -0,0 +1,1069 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" + integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/eslint-scope@^3.7.3": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" + integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.44.2" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.2.tgz#0d21c505f98a89b8dd4d37fa162b09da6089199a" + integrity sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + +"@types/json-schema@*", "@types/json-schema@^7.0.8": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/node@*": + version "20.4.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.8.tgz#b5dda19adaa473a9bf0ab5cbd8f30ec7d43f5c85" + integrity sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg== + +"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" + integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" + integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" + integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" + integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-opt" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + "@webassemblyjs/wast-printer" "1.11.6" + +"@webassemblyjs/wasm-gen@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" + integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" + integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-buffer" "1.11.6" + "@webassemblyjs/wasm-gen" "1.11.6" + "@webassemblyjs/wasm-parser" "1.11.6" + +"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" + integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" + integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== + dependencies: + "@webassemblyjs/ast" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +acorn-import-assertions@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" + integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.14.5: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== + +chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^9.0.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dotenv-cli@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-7.2.1.tgz#e595afd9ebfb721df9da809a435b9aa966c92062" + integrity sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ== + dependencies: + cross-spawn "^7.0.3" + dotenv "^16.0.0" + dotenv-expand "^10.0.0" + minimist "^1.2.6" + +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + +dotenv@^16.0.0: + version "16.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" + integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== + +electron-to-chromium@^1.4.477: + version "1.4.487" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.487.tgz#e2ef8b15f2791bf68fa6f38f2656f1a551d360ae" + integrity sha512-XbCRs/34l31np/p33m+5tdBrdXu9jJkZxSbNxj5I0H1KtV2ZMSB+i/HYqDiRzHaFx2T5EdytjoBRe8QRJE2vQg== + +enhanced-resolve@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +envinfo@^7.7.3: + version "7.10.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.10.0.tgz#55146e3909cc5fe63c22da63fb15b05aeac35b13" + integrity sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw== + +es-module-lexer@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" + integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +globby@^11.0.4: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mylas@^2.1.9: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mylas/-/mylas-2.1.13.tgz#1e23b37d58fdcc76e15d8a5ed23f9ae9fc0cbdf4" + integrity sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +plimit-lit@^1.2.6: + version "1.5.0" + resolved "https://registry.yarnpkg.com/plimit-lit/-/plimit-lit-1.5.0.tgz#f66df8a7041de1e965c4f1c0697ab486968a92a5" + integrity sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng== + dependencies: + queue-lit "^1.5.0" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-lit@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/queue-lit/-/queue-lit-1.5.0.tgz#8197fdafda1edd615c8a0fc14c48353626e5160a" + integrity sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +serialize-javascript@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.7: + version "5.3.9" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" + integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.16.8" + +terser@^5.16.8: + version "5.19.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" + integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tsc-alias@^1.8.7: + version "1.8.7" + resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.7.tgz#4f8721b031a31345fa9f1fa8d3cf209d925abb88" + integrity sha512-59Q/zUQa3miTf99mLbSqaW0hi1jt4WoG8Uhe5hSZJHQpSoFW9eEwvW7jlKMHXWvT+zrzy3SN9PE/YBhQ+WVydA== + dependencies: + chokidar "^3.5.3" + commander "^9.0.0" + globby "^11.0.4" + mylas "^2.1.9" + normalize-path "^3.0.0" + plimit-lit "^1.2.6" + +tsc@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/tsc/-/tsc-2.0.4.tgz#5f6499146abea5dca4420b451fa4f2f9345238f5" + integrity sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q== + +typescript@5.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +watchpack@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webpack-cli@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-merge@^5.7.3: + version "5.9.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.9.0.tgz#dc160a1c4cf512ceca515cc231669e9ddb133826" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.88.2: + version "5.88.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" + integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.0" + "@webassemblyjs/ast" "^1.11.5" + "@webassemblyjs/wasm-edit" "^1.11.5" + "@webassemblyjs/wasm-parser" "^1.11.5" + acorn "^8.7.1" + acorn-import-assertions "^1.9.0" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.15.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.7" + watchpack "^2.4.0" + webpack-sources "^3.2.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== diff --git a/deploy/values/l2-optimism-goerli/values.yaml b/deploy/values/l2-optimism-goerli/values.yaml index d3efba3f3e..44ab591f34 100644 --- a/deploy/values/l2-optimism-goerli/values.yaml +++ b/deploy/values/l2-optimism-goerli/values.yaml @@ -186,7 +186,6 @@ frontend: NEXT_PUBLIC_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json NEXT_PUBLIC_NETWORK_EXPLORERS: '' NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)" - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: '' NEXT_PUBLIC_NETWORK_RPC_URL: https://goerli.optimism.io NEXT_PUBLIC_WEB3_DEFAULT_WALLET: coinbase NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: true @@ -199,6 +198,5 @@ frontend: NEXT_PUBLIC_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 envFromSecret: - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: ref+vault://deployment-values/blockscout/dev/l2-optimism-goerli?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/l2-optimism-goerli?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/l2-optimism-goerli?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID diff --git a/deploy/values/main/values.yaml b/deploy/values/main/values.yaml index 9736943a80..6736e4f3f0 100644 --- a/deploy/values/main/values.yaml +++ b/deploy/values/main/values.yaml @@ -144,7 +144,6 @@ frontend: NEXT_PUBLIC_NETWORK_LOGO: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/goerli.svg NEXT_PUBLIC_NETWORK_ICON: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/goerli.svg - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE: validation NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: https://airtable.com/shrqUAcjgGJ4jU88C NEXT_PUBLIC_APP_ENV: stable @@ -160,7 +159,6 @@ frontend: NEXT_PUBLIC_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d envFromSecret: - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI NEXT_PUBLIC_AUTH0_CLIENT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_AUTH0_CLIENT_ID diff --git a/deploy/values/review-l2/values.yaml.gotmpl b/deploy/values/review-l2/values.yaml.gotmpl index 97305e8ed4..e90f598604 100644 --- a/deploy/values/review-l2/values.yaml.gotmpl +++ b/deploy/values/review-l2/values.yaml.gotmpl @@ -107,8 +107,6 @@ frontend: _default: '' NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: _default: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)" - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: - _default: '' NEXT_PUBLIC_NETWORK_RPC_URL: _default: https://goerli.optimism.io NEXT_PUBLIC_WEB3_DEFAULT_WALLET: @@ -133,8 +131,6 @@ frontend: _default: https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_GRAPHIQL_TRANSACTION: _default: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: - _default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS NEXT_PUBLIC_SENTRY_DSN: _default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN SENTRY_CSP_REPORT_URI: diff --git a/deploy/values/review/values.yaml.gotmpl b/deploy/values/review/values.yaml.gotmpl index b9f53f636a..2866be05f3 100644 --- a/deploy/values/review/values.yaml.gotmpl +++ b/deploy/values/review/values.yaml.gotmpl @@ -111,8 +111,6 @@ frontend: _default: true NEXT_PUBLIC_GRAPHIQL_TRANSACTION: _default: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS: - _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS NEXT_PUBLIC_SENTRY_DSN: _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN SENTRY_CSP_REPORT_URI: diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index f8f667d51a..c8e3598963 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -59,7 +59,7 @@ For all types of dependencies: These are the steps that you have to follow to make everything work: 1. First and foremost, document variable in the [/docs/ENVS.md](./ENVS.md) file; provide short description, its expected type, requirement flag, default and example value; **do not skip this step** otherwise the app will not receive variable value at run-time -2. Make sure that you have added a property to React app config (`/configs/app/config.ts`) that is associated with this variable; do not use ENV variable values directly in the application code +2. Make sure that you have added a property to React app config (`/configs/app/index.ts`) in appropriate section that is associated with this variable; do not use ENV variable values directly in the application code 3. For local development purposes add the variable with its appropriate values to pre-defined ENV configs `/configs/envs` where it is needed 4. Add the variable to CI configs where it is needed - `deploy/values/review/values.yaml.gotmpl` - review development environment diff --git a/docs/ENVS.md b/docs/ENVS.md index 392167ce29..0b85d02156 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -1,71 +1,304 @@ # Run-time environment variables -The app instance could be customized by passing following variables to NodeJS environment at runtime. See their list below. +The app instance could be customized by passing following variables to NodeJS environment at run-time. See their list below. **IMPORTANT NOTE!** For _production_ build purposes all json-like values should be single-quoted. If it contains a hash (`#`) or a dollar-sign (`$`) the whole value should be wrapped in single quotes as well (see `dotenv` [readme](https://github.com/bkeepers/dotenv#variable-substitution) for the reference) -## Network configuration +## Table of contents +- [App configuration](ENVS.md#app-configuration) +- [Blockchain parameters](ENVS.md#blockchain-parameters) +- [API configuration](ENVS.md#api-configuration) +- [UI configuration](ENVS.md#ui-configuration) + - [Homepage](ENVS.md#homepage) + - [Sidebar](ENVS.md#sidebar) + - [Footer](ENVS.md#footer) + - [Misc](ENVS.md#misc) +- [App features](ENVS.md#app-features) + - [My account](ENVS.md#my-account) + - [Address verification](ENVS.md#address-verification-in-my-account) in "My account" + - [Blockchain interaction](ENVS.md#blockchain-interaction-writing-to-contract-etc) (writing to contract, etc.) + - [Banner ads](ENVS.md#banner-ads) + - [Text ads](ENVS.md#text-ads) + - [Beacon chain](ENVS.md#beacon-chain) + - [Rollup (L2) chain](ENVS.md#rollup-l2-chain) + - [Export data to CSV file](ENVS.md#export-data-to-csv-file) + - [Google analytics](ENVS.md#google-analytics) + - [Mixpanel analytics](ENVS.md#mixpanel-analytics) + - [GraphQL API documentation](ENVS.md#graphql-api-documentation) + - [REST API documentation](ENVS.md#rest-api-documentation) + - [Marketplace](ENVS.md#marketplace) + - [Solidity to UML diagrams](ENVS.md#solidity-to-uml-diagrams) + - [Blockchain statistics](ENVS.md#blockchain-statistics) + - [Web3 wallet integration](ENVS.md#web3-wallet-integration-add-token-or-network-to-the-wallet) (add token or network to the wallet) + - [Verified tokens info](ENVS.md#verified-tokens-info) + - [Sentry error monitoring](ENVS.md#sentry-error-monitoring) +- [3rd party services configuration](ENVS.md#external-services-configuration) -| Variable | Type| Description | Is required | Default value | Example value | +  + +## App configuration + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_APP_PROTOCOL | `http \| https` | App url schema | - | `https` | `http` | +| NEXT_PUBLIC_APP_HOST | `string` | App host | Required | - | `blockscout.com` | +| NEXT_PUBLIC_APP_PORT | `number` | Port where app is running | - | `3000` | `3001` | +| NEXT_PUBLIC_USE_NEXT_JS_PROXY | `boolean` | Tells the app to proxy all APIs request through the NextJS app. **We strongly advise not to use it in the production environment**, since it can lead to performance issues of the NodeJS server | - | `false` | `true` | + +  + +## Blockchain parameters + +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_NETWORK_NAME | `string` | Displayed name of the network | yes | - | `Gnosis Chain` | -| NEXT_PUBLIC_NETWORK_SHORT_NAME | `string` | Used for SEO attributes (page title and description) | - | - | `OoG` | -| NEXT_PUBLIC_NETWORK_ID | `number` | Chain id, see [https://chainlist.org](https://chainlist.org) for the reference | yes | - | `99` | -| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | Chain server RPC url, see [https://chainlist.org](https://chainlist.org) for the reference. If not provided, some functionality of the explorer, related to smart contracts interaction and third-party apps integration, will be unavailable | - | - | `https://core.poa.network` | +| NEXT_PUBLIC_NETWORK_NAME | `string` | Displayed name of the network | Required | - | `Gnosis Chain` | +| NEXT_PUBLIC_NETWORK_SHORT_NAME | `string` | Used for SEO attributes (e.g, page description) | - | - | `OoG` | +| NEXT_PUBLIC_NETWORK_ID | `number` | Chain id, see [https://chainlist.org](https://chainlist.org) for the reference | Required | - | `99` | +| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | Chain public RPC server url, see [https://chainlist.org](https://chainlist.org) for the reference | - | - | `https://core.poa.network` | | NEXT_PUBLIC_NETWORK_CURRENCY_NAME | `string` | Network currency name | - | - | `Ether` | | NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL | `string` | Network currency symbol | - | - | `ETH` | | NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS | `string` | Network currency decimals | - | `18` | `6` | -| NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS | `string` | Address of network's native token | - | - | `0x029a799563238d0e75e20be2f4bda0ea68d00172` | -| NEXT_PUBLIC_NETWORK_LOGO | `string` | Network logo; if not provided, placeholder will be shown; *Note* the logo height should be 20px and width less than 120px | - | - | `https://placekitten.com/240/40` | -| NEXT_PUBLIC_NETWORK_LOGO_DARK | `string` | Network logo for dark color mode; if not provided, **inverted** regular logo will be used instead | - | - | `https://placekitten.com/240/40` | -| NEXT_PUBLIC_NETWORK_ICON | `string` | Network icon; used as a replacement for regular network logo when nav bar is collapsed; if not provided, placeholder will be shown; *Note* the icon size should be at least 60px by 60px | - | - | `https://placekitten.com/60/60` | -| NEXT_PUBLIC_NETWORK_ICON_DARK | `string` | Network icon for dark color mode; if not provided, **inverted** regular icon will be used instead | - | - | `https://placekitten.com/60/60` | +| NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE | `validation` or `mining` | Verification type in the network | - | `mining` | `validation` | | NEXT_PUBLIC_IS_TESTNET | `boolean`| Set to true if network is testnet | - | `false` | `true` | +  + +## API configuration + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_API_PROTOCOL | `http \| https` | Main API protocol | - | `https` | `http` | +| NEXT_PUBLIC_API_HOST | `string` | Main API host | Required | - | `blockscout.com` | +| NEXT_PUBLIC_API_PORT | `number` | Port where API is running on the host | - | - | `3001` | +| NEXT_PUBLIC_API_BASE_PATH | `string` | Base path for Main API endpoint url | - | - | `/poa/core` | +| NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL | `ws \| wss` | Main API websocket protocol | - | `wss` | `ws` | + +  + ## UI configuration -| Variable | Type| Description | Is required | Default value | Example value | +### Homepage + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'market_cap'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` | +| NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR | `string` | Text color of the hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead) | - | `white` | `\#DCFE76` | +| NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND | `string` | Background css value for hero plate on the homepage (escape "#" symbol if you use HEX color codes or use rgba-value instead) | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%)` \| `no-repeat bottom 20% right 0px/100% url(https://placekitten/1400/200)` | +| NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` | Set to false if network doesn't have gas tracker | - | `true` | `false` | +| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` | Set to false if average block time is useless for the network | - | `true` | `false` | + +  + +### Sidebar + +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_NETWORK_LOGO | `string` | Network logo; if not provided, placeholder will be shown; *Note* the logo height should be 20px and width less than 120px | - | - | `https://placekitten.com/240/40` | +| NEXT_PUBLIC_NETWORK_LOGO_DARK | `string` | Network logo for dark color mode; if not provided, **inverted** regular logo will be used instead | - | - | `https://placekitten.com/240/40` | +| NEXT_PUBLIC_NETWORK_ICON | `string` | Network icon; used as a replacement for regular network logo when nav bar is collapsed; if not provided, placeholder will be shown; *Note* the icon size should be at least 60px by 60px | - | - | `https://placekitten.com/60/60` | +| NEXT_PUBLIC_NETWORK_ICON_DARK | `string` | Network icon for dark color mode; if not provided, **inverted** regular icon will be used instead | - | - | `https://placekitten.com/60/60` | | NEXT_PUBLIC_FEATURED_NETWORKS | `string` | URL of configuration file (`.json` format only) which contains list of featured networks that will be shown in the network menu. See [below](#featured-network-configuration-properties) list of available properties for particular network | - | - | `https://example.com/featured_networks_config.json` | | NEXT_PUBLIC_OTHER_LINKS | `Array<{url: string; text: string}>` | List of links for the "Other" navigation menu | - | - | `[{'url':'https://blockscout.com','text':'Blockscout'}]` | + +#### Featured network configuration properties + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| title | `string` | Displayed name of the network | Required | - | `Gnosis Chain` | +| url | `string` | Network explorer main page url | Required | - | `https://blockscout.com/xdai/mainnet` | +| group | `Mainnets \| Testnets \| Other` | Indicates in which tab network appears in the menu | Required | - | `Mainnets` | +| icon | `string` | Network icon; if not provided, the common placeholder will be shown; *Note* that icon size should be at least 60px by 60px | - | - | `https://placekitten.com/60/60` | +| isActive | `boolean` | Pass `true` if item should be shonw as active in the menu | - | - | `true` | +| invertIconInDarkMode | `boolean` | Pass `true` if icon colors should be inverted in dark mode | - | - | `true` | + +  + +### Footer + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | | NEXT_PUBLIC_FOOTER_LINKS | `string` | URL of configuration file (`.json` format only) which contains list of link groups to be displayed in the footer. See [below](#footer-links-configuration-properties) list of available properties for particular group | - | - | `https://example.com/footer_links_config.json` | -| NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app | - | - | `https://example.com/marketplace_config.json` | -| NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM | `string` | Link to form where authors can submit their dapps to the marketplace | - | - | `https://airtable.com/shrqUAcjgGJ4jU88C` | + +The app version shown in the footer is derived from build-time ENV variables `NEXT_PUBLIC_GIT_TAG` and `NEXT_PUBLIC_GIT_COMMIT_SHA` and cannot be overwritten at run-time. + +#### Footer links configuration properties + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| title | `string` | Title of link group | Required | - | `Company` | +| links | `Array<{'text':string;'url':string;}>` | list of links | Required | - | `[{'text':'Homepage','url':'https://www.blockscout.com'}]` | + +  + +### Misc + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | | NEXT_PUBLIC_NETWORK_EXPLORERS | `Array` where `NetworkExplorer` can have following [properties](#network-explorer-configuration-properties) | Used to build up links to transactions, blocks, addresses in other chain explorers. | - | - | `[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/tx'}}]` | -| NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE | `validation` or `mining` | Verification type in the network | - | `mining` | `validation` | -| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'market_cap'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` | -| NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR | `string` | Text color of the hero plate on the homepage (escape "#" symbol if you use HEX color codes) | `\#FFFFFF \| rgb(220, 254, 118)` | `\#DCFE76` | -| NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND | `string` | Background css value for hero plate on the homepage (escape "#" symbol if you use HEX color codes) | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%)` \| `no-repeat bottom 20% right 0px/100% url(https://placekitten/1400/200)` | -| NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` | Set to false if network doesn't have gas tracker | - | `true` | `false` | -| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` | Set to false if average block time is useless for the network | - | `true` | `false` | +| NEXT_PUBLIC_HIDE_INDEXING_ALERT | `boolean` | Set to `true` to hide indexing alert, if the chain indexing isn't completed | - | `false` | `true` | + +#### Network explorer configuration properties + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| title | `string` | Displayed name of the explorer | Required | - | `Anyblock` | +| baseUrl | `string` | Base url of the explorer | Required | - | `https://explorer.anyblock.tools` | +| paths | `Record<'tx' \| 'block' \| 'address' \| 'token', string>` | Map of explorer entities and their paths | Required | - | `{'tx':'/ethereum/poa/core/tx'}` | + +*Note* The url of an entity will be constructed as `]>`, e.g `https://explorer.anyblock.tools/ethereum/poa/core/tx/` + +  + +## App features + +*Note* The variables which are marked as required should be passed as described in order to enable the particular feature, but there are not required in the whole app context. + +### My account + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED | `boolean` | Set to true if network has account feature | Required | - | `true` | +| NEXT_PUBLIC_AUTH0_CLIENT_ID | `string` | Client id for [Auth0](https://auth0.com/) provider | Required | - | `` | +| NEXT_PUBLIC_AUTH_URL | `string` | Account auth base url; it is used for building login URL (`${ NEXT_PUBLIC_AUTH_URL }/auth/auth0`) and logout return URL (`${ NEXT_PUBLIC_AUTH_URL }/auth/logout`); if not provided the base app URL will be used instead | Required | - | `https://blockscout.com` | +| NEXT_PUBLIC_LOGOUT_URL | `string` | Account logout url. Required if account is supported for the app instance. | Required | - | `https://blockscoutcom.us.auth0.com/v2/logout` | + +  + +### Address verification in "My account" + +*Note* all ENV variables required for [My account](ENVS.md#my-account) feature should be passed along side with the following ones: + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | Required | - | `https://contracts-info.services.blockscout.com` | +| NEXT_PUBLIC_ADMIN_SERVICE_API_HOST | `string` | Admin Service API endpoint url | Required | - | `https://admin-rs.services.blockscout.com` | + +  + +### Blockchain interaction (writing to contract, etc.) + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID | `string` | Project id for [WalletConnect](https://docs.walletconnect.com/2.0/web3modal/react/installation#obtain-project-id) integration | Required | - | `` | +| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `https://core.poa.network` | +| NEXT_PUBLIC_NETWORK_NAME | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `Gnosis Chain` | +| NEXT_PUBLIC_NETWORK_ID | `number` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `99` | +| NEXT_PUBLIC_NETWORK_CURRENCY_NAME | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `Ether` | +| NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `ETH` | +| NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | - | `18` | `6` | + +  + +### Banner ads + +This feature is **enabled by default** with the `slise` ads provider. To switch it off pass `NEXT_PUBLIC_AD_BANNER_PROVIDER=none`. + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `none` | Ads provider | - | `slise` | `coinzilla` | | NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` | | NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` | -| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `none` | Banner ad provider. Set to `none` to disable ad banners | - | `slise` | `coinzilla` | -| NEXT_PUBLIC_AD_TEXT_PROVIDER | `coinzilla` \| `none` | Text ad provider. Set to `none` to disable text ad | - | `coinzilla` | `none` | -| NEXT_PUBLIC_API_SPEC_URL | `string` | Spec to be displayed on api-docs page | - | - | `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml` | -| NEXT_PUBLIC_GRAPHIQL_TRANSACTION | `string` | Txn hash for default query at GraphQl playground page | - | - | `0x69e3923eef50eada197c3336d546936d0c994211492c9f947a24c02827568f9f` | -| NEXT_PUBLIC_WEB3_DEFAULT_WALLET | `metamask` \| `coinbase`| Type of Web3 wallet which will be used by default to add tokens or chains to | - | `metamask` | `coinbase` | -| NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET | `boolean`| Set to `true` to hide icon "Add to your wallet" next to token addresses | - | `false` | `true` | -| NEXT_PUBLIC_HIDE_INDEXING_ALERT | `boolean` | Set to `true` to hide indexing alert, if the chain indexing isn't completed | - | `false` | `true` | -### Marketplace app configuration properties - -| Property | Type | Description | Example value -| --- | --- | --- | --- | -| id | `string` | Used as slug for the app. Must be unique in the app list. | `'app'` | -| external | `boolean` | If true means that the application opens in a new window, but not in an iframe. | `true` | -| title | `string` | Displayed title of the app. | `'The App'` | -| logo | `string` | URL to logo file. Should be at least 288x288. | `'https://foo.app/icon.png'` | -| shortDescription | `string` | Displayed only in the app list. | `'Awesome app'` | -| categories | `Array` | Displayed category. Select one of the following bellow. | `['security', 'tools']` | -| author | `string` | Displayed author of the app | `'Bob'` | -| url | `string` | URL of the app which will be launched in the iframe. | `'https://foo.app/launch'` | -| description | `string` | Displayed only in the modal dialog with additional info about the app. | `'The best app'` | -| site | `string` *(optional)* | Displayed site link | `'https://blockscout.com'` | -| twitter | `string` *(optional)* | Displayed twitter link | `'https://twitter.com/blockscoutcom'` | -| telegram | `string` *(optional)* | Displayed telegram link | `'https://t.me/poa_network'` | -| github | `string` *(optional)* | Displayed github link | `'https://github.com/blockscout'` | - -### Marketplace categories ids + +  + +### Text ads + +This feature is **enabled by default** with the `coinzilla` ads provider. To switch it off pass `NEXT_PUBLIC_AD_TEXT_PROVIDER=none`. + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_AD_TEXT_PROVIDER | `coinzilla` \| `none` | Ads provider | - | `coinzilla` | `none` | + +  + +### Beacon chain + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_HAS_BEACON_CHAIN | `boolean` | Set to true for networks with the beacon chain | Required | - | `true` | +| NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL | `string` | Beacon network currency symbol | - | `NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL` | `ETH` | + +  + +### Rollup (L2) chain + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_IS_L2_NETWORK | `boolean` | Set to true for L2 solutions | Required | - | `true` | +| NEXT_PUBLIC_L1_BASE_URL | `string` | Blockscout base URL for L1 network | Required | - | `'http://eth-goerli.blockscout.com'` | +| NEXT_PUBLIC_L2_WITHDRAWAL_URL | `string` | URL for L2 -> L1 withdrawals | Required | - | `https://app.optimism.io/bridge/withdraw` | + +  + +### Export data to CSV file + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY | `string` | See [below](ENVS.md#google-recaptcha) | true | - | `` | + +  + +### Google analytics + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID | `string` | Property ID for [Google Analytics](https://analytics.google.com/) service | true | - | `UA-XXXXXX-X` | + +  + +### Mixpanel analytics + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN | `string` | Project token for [Mixpanel](https://mixpanel.com/) analytics service | true | - | `` | + +  + +### GraphQL API documentation + +This feature is **always enabled**, but you can configure its behavior by passing the following variables. + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_GRAPHIQL_TRANSACTION | `string` | Txn hash for default query at GraphQl playground page | - | - | `0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62` | + +  + +### REST API documentation + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_API_SPEC_URL | `string` | Spec to be displayed on `/api-docs` page | Required | - | `https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml` | + +  + +### Marketplace + +| Variable | Type| Description | Compulsoriness | Default value | Example value | +| --- | --- | --- | --- | --- | --- | +| NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app | Required | - | `https://example.com/marketplace_config.json` | +| NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM | `string` | Link to form where authors can submit their dapps to the marketplace | Required | - | `https://airtable.com/shrqUAcjgGJ4jU88C` | +| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `https://core.poa.network` | + +#### Marketplace app configuration properties + +| Property | Type | Description | Compulsoriness | Example value +| --- | --- | --- | --- | --- | +| id | `string` | Used as slug for the app. Must be unique in the app list. | Required | `'app'` | +| external | `boolean` | `true` means that the application opens in a new window, but not in an iframe. | - | `true` | +| title | `string` | Displayed title of the app. | Required | `'The App'` | +| logo | `string` | URL to logo file. Should be at least 288x288. | Required | `'https://foo.app/icon.png'` | +| shortDescription | `string` | Displayed only in the app list. | Required | `'Awesome app'` | +| categories | `Array` | Displayed category. Select one of the following bellow. | Required | `['security', 'tools']` | +| author | `string` | Displayed author of the app | Required | `'Bob'` | +| url | `string` | URL of the app which will be launched in the iframe. | Required | `'https://foo.app/launch'` | +| description | `string` | Displayed only in the modal dialog with additional info about the app. | Required | `'The best app'` | +| site | `string` | Displayed site link | - | `'https://blockscout.com'` | +| twitter | `string` | Displayed twitter link | - | `'https://twitter.com/blockscoutcom'` | +| telegram | `string` | Displayed telegram link | - | `'https://t.me/poa_network'` | +| github | `string` | Displayed github link | - | `'https://github.com/blockscout'` | + +#### Marketplace categories ids For each application, you need to specify the `MarketplaceCategoryId` to which it belongs. Select one of the following: @@ -80,94 +313,60 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i - `tools` - `yieldFarming` -### Featured network configuration properties - -| Variable | Type| Description | Is required | Default value | Example value | -| --- | --- | --- | --- | --- | --- | -| title | `string` | Displayed name of the network | yes | - | `Gnosis Chain` | -| url | `string` | Network explorer main page url | yes | - | `https://blockscout.com/xdai/mainnet` | -| group | `Mainnets \| Testnets \| Other` | Indicates in which tab network appears in the menu | yes | - | `Mainnets` | -| icon | `string` | Network icon; if not provided, the common placeholder will be shown; *Note* that icon size should be at least 60px by 60px | - | - | `https://placekitten.com/60/60` | -| isActive | `boolean` | Pass `true` if item should be shonw as active in the menu | - | - | `true` | -| invertIconInDarkMode | `boolean` | Pass `true` if icon colors should be inverted in dark mode | - | - | `true` | +  -### Network explorer configuration properties +### Solidity to UML diagrams -| Variable | Type| Description | Is required | Default value | Example value | +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| title | `string` | Displayed name of the explorer | yes | - | `Anyblock` | -| baseUrl | `string` | Base url of the explorer | yes | - | `https://explorer.anyblock.tools` | -| paths | `Record<'tx' \| 'block' \| 'address' \| 'token', string>` | Map of explorer entities and their paths | yes | - | `{'tx':'/ethereum/poa/core/tx'}` | +| NEXT_PUBLIC_VISUALIZE_API_HOST | `string` | Visualize API endpoint url | Required | - | `https://visualizer.services.blockscout.com` | -*Note* The url of an entity will be constructed as `]>`, e.g `https://explorer.anyblock.tools/ethereum/poa/core/tx/` +  -### Footer links configuration properties +### Blockchain statistics -| Variable | Type| Description | Is required | Default value | Example value | +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| title | `string` | Title of link group | yes | - | `Company` | -| links | `Array<{'text':string;'url':string;}>` | list of links | yes | - | `[{'text':'Homepage','url':'https://www.blockscout.com'}]` | +| NEXT_PUBLIC_STATS_API_HOST | `string` | API endpoint url | Required | - | `https://stats.services.blockscout.com` | -## Account configuration +  -In order to enable "My Account" feature you have to configure following set of variables. All variables are **required**. +### Web3 wallet integration (add token or network to the wallet) -| Variable | Type| Description | Is required | Default value | Example value | -| --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED | `boolean` | Set to true if network has account feature | yes | `false` | `true` | -| NEXT_PUBLIC_AUTH0_CLIENT_ID | `string` | Client id for [Auth0](https://auth0.com/) provider | yes | - | `` | -| NEXT_PUBLIC_AUTH_URL | `string` | Account auth base url; it is used for building login URL (`${ NEXT_PUBLIC_AUTH_URL }/auth/auth0`) and logout return URL (`${ NEXT_PUBLIC_AUTH_URL }/auth/logout`); if not provided the base app URL will be used instead | yes | - | `https://blockscout.com` | -| NEXT_PUBLIC_LOGOUT_URL | `string` | Account logout url. Required if account is supported for the app instance. | yes | - | `https://blockscoutcom.us.auth0.com/v2/logout` | +This feature is **enabled by default** with the `metamask` wallet type. To switch it off pass `NEXT_PUBLIC_WEB3_DEFAULT_WALLET=none`. -## App configuration - -| Variable | Type| Description | Is required | Default value | Example value | +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance | - | - | `wonderful_kepler` | -| NEXT_PUBLIC_APP_PROTOCOL | `http \| https` | App url schema | - | `https` | `http` | -| NEXT_PUBLIC_APP_HOST | `string` | App host | yes | - | `blockscout.com` | -| NEXT_PUBLIC_APP_PORT | `number` | Port where app is running | - | `3000` | `3001` | -| NEXT_PUBLIC_APP_ENV | `string` | Current app env (e.g development, review or production). Used for Sentry.io configuration | - | equals to `process.env.NODE_ENV` | `production` | -| NEXT_PUBLIC_USE_NEXT_JS_PROXY | `boolean` | Tells the app to proxy all APIs request through the NextJs app. **We strongly advise not to use it in the production environment** | - | `false` | `true` | +| NEXT_PUBLIC_WEB3_DEFAULT_WALLET | `metamask` \| `coinbase` \| `none` | Type of Web3 wallet which will be used by default to add tokens or chains to | - | `metamask` | `coinbase` | +| NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET | `boolean`| Set to `true` to hide icon "Add to your wallet" next to token addresses | - | - | `true` | -## API configuration +  -| Variable | Type| Description | Is required | Default value | Example value | +### Verified tokens info + +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_API_PROTOCOL | `http \| https` | Main API protocol | - | `https` | `http` | -| NEXT_PUBLIC_API_HOST | `string` | Main API host | yes | - | `blockscout.com` | -| NEXT_PUBLIC_API_PORT | `number` | Port where API is running on the host | - | - | `3001` | -| NEXT_PUBLIC_API_BASE_PATH | `string` | Base path for Main API endpoint url | - | - | `/poa/core` | -| NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL | `ws \| wss` | Main API websocket protocol | - | `wss` | `ws` | -| NEXT_PUBLIC_STATS_API_HOST | `string` | Stats API endpoint url | - | - | `https://stats.services.blockscout.com` | -| NEXT_PUBLIC_VISUALIZE_API_HOST | `string` | Visualize API endpoint url | - | - | `https://visualizer.services.blockscout.com` | -| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | - | - | `https://contracts-info.services.blockscout.com` | -| NEXT_PUBLIC_ADMIN_SERVICE_API_HOST | `string` | Admin Service API endpoint url | - | - | `https://admin-rs.services.blockscout.com` | +| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | Required | - | `https://contracts-info.services.blockscout.com` | +  -## External services configuration +### Sentry error monitoring -| Variable | Type| Description | Is required | Default value | Example value | +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_SENTRY_DSN | `string` | Client key for your Sentry.io app | - | - | `` | -| SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `` | -| NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID | `string` | Project id for [WalletConnect](https://docs.walletconnect.com/2.0/web3modal/react/installation#obtain-project-id) integration | - | - | `` | -| NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY | `string` | Site key for [reCAPTCHA](https://developers.google.com/recaptcha) service | - | - | `` | -| NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID | `string` | Property ID for [Google Analytics](https://analytics.google.com/) service | - | - | `UA-XXXXXX-X` | -| NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN | `string` | Project token for [Mixpanel](https://mixpanel.com/) analytics service | - | - | `` | +| NEXT_PUBLIC_SENTRY_DSN | `string` | Client key for your Sentry.io app | Required | - | `` | +| SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `` | +| NEXT_PUBLIC_APP_ENV | `string` | Current app env (e.g development, review or production). Passed as `environment` property to Sentry config | - | `process.env.NODE_ENV` | `production` | +| NEXT_PUBLIC_APP_INSTANCE | `string` | Name of app instance. Used as custom tag `app_instance` value in the main Sentry scope | - | - | `wonderful_kepler` | -## L2 configuration -*Note* All variables are required only for roll-up instances +  -| Variable | Type| Description | Is required | Default value | Example value | -| --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_IS_L2_NETWORK | `boolean` | Set to true for L2 solutions (Optimism Bedrock based) | yes | - | `true` | -| NEXT_PUBLIC_L1_BASE_URL | `string` | Base Blockscout URL for L1 network | yes | - | `'http://eth-goerli.blockscout.com'` | -| NEXT_PUBLIC_L2_WITHDRAWAL_URL | `string` | URL for L2 -> L1 withdrawals | yes | - | `https://app.optimism.io/bridge/withdraw` | +## External services configuration + +### Google ReCaptcha -## Beacon chain configuration +For obtaining the variables values please refer to [reCAPTCHA documentation](https://developers.google.com/recaptcha). -| Variable | Type| Description | Is required | Default value | Example value | +| Variable | Type| Description | Compulsoriness | Default value | Example value | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_HAS_BEACON_CHAIN | `boolean` | Set to true for networks with the beacon chain | - | - | `true` | -| NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL | `string` | Beacon network currency symbol | - | NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL | `ETH` | +| NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY | `string` | Site key | - | - | `` | diff --git a/lib/api/buildUrl.ts b/lib/api/buildUrl.ts index 9ed95caae9..2feb358e1c 100644 --- a/lib/api/buildUrl.ts +++ b/lib/api/buildUrl.ts @@ -1,6 +1,6 @@ import { compile } from 'path-to-regexp'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import isNeedProxy from './isNeedProxy'; import { RESOURCES } from './resources'; @@ -12,8 +12,8 @@ export default function buildUrl( queryParams?: Record | number | null | undefined>, ): string { const resource: ApiResource = RESOURCES[resourceName]; - const baseUrl = isNeedProxy() ? appConfig.app.baseUrl : (resource.endpoint || appConfig.api.endpoint); - const basePath = resource.basePath !== undefined ? resource.basePath : appConfig.api.basePath; + const baseUrl = isNeedProxy() ? config.app.baseUrl : (resource.endpoint || config.api.endpoint); + const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath; const path = isNeedProxy() ? '/node-api/proxy' + basePath + resource.path : basePath + resource.path; const url = new URL(compile(path)(pathParams), baseUrl); diff --git a/lib/api/buildUrlNode.ts b/lib/api/buildUrlNode.ts index 1878249fec..cfe63caf94 100644 --- a/lib/api/buildUrlNode.ts +++ b/lib/api/buildUrlNode.ts @@ -1,6 +1,6 @@ import { compile } from 'path-to-regexp'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { RESOURCES } from './resources'; import type { ApiResource, ResourceName } from './resources'; @@ -11,8 +11,8 @@ export default function buildUrlNode( queryParams?: Record, ) { const resource: ApiResource = typeof _resource === 'string' ? RESOURCES[_resource] : _resource; - const baseUrl = resource.endpoint || appConfig.api.endpoint; - const basePath = resource.basePath !== undefined ? resource.basePath : appConfig.api.basePath; + const baseUrl = resource.endpoint || config.api.endpoint; + const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath; const path = basePath + resource.path; const url = new URL(compile(path)(pathParams), baseUrl); diff --git a/lib/api/isNeedProxy.ts b/lib/api/isNeedProxy.ts index a348a196f7..a7705091e4 100644 --- a/lib/api/isNeedProxy.ts +++ b/lib/api/isNeedProxy.ts @@ -1,13 +1,13 @@ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; // FIXME // I was not able to figure out how to send CORS with credentials from localhost // unsuccessfully tried different ways, even custom local dev domain // so for local development we have to use next.js api as proxy server export default function isNeedProxy() { - if (appConfig.app.useNextJsProxy) { + if (config.app.useProxy) { return true; } - return appConfig.app.host === 'localhost' && appConfig.app.host !== appConfig.api.host; + return config.app.host === 'localhost' && config.app.host !== config.api.host; } diff --git a/lib/api/resources.ts b/lib/api/resources.ts index 0e690c50d8..800f5963bd 100644 --- a/lib/api/resources.ts +++ b/lib/api/resources.ts @@ -59,7 +59,7 @@ import type { VisualizedContract } from 'types/api/visualization'; import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals'; import type { ArrayElement } from 'types/utils'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export interface ApiResource { path: ResourcePath; @@ -111,58 +111,58 @@ export const RESOURCES = { address_verification: { path: '/api/v1/chains/:chainId/verified-addresses:type', pathParams: [ 'chainId' as const, 'type' as const ], - endpoint: appConfig.contractInfoApi.endpoint, - basePath: appConfig.contractInfoApi.basePath, + endpoint: config.features.verifiedTokens.api.endpoint, + basePath: config.features.verifiedTokens.api.basePath, needAuth: true, }, verified_addresses: { path: '/api/v1/chains/:chainId/verified-addresses', pathParams: [ 'chainId' as const ], - endpoint: appConfig.contractInfoApi.endpoint, - basePath: appConfig.contractInfoApi.basePath, + endpoint: config.features.verifiedTokens.api.endpoint, + basePath: config.features.verifiedTokens.api.basePath, needAuth: true, }, token_info_applications_config: { path: '/api/v1/chains/:chainId/token-info-submissions/selectors', pathParams: [ 'chainId' as const ], - endpoint: appConfig.adminServiceApi.endpoint, - basePath: appConfig.adminServiceApi.basePath, + endpoint: config.features.addressVerification.api.endpoint, + basePath: config.features.addressVerification.api.basePath, needAuth: true, }, token_info_applications: { path: '/api/v1/chains/:chainId/token-info-submissions/:id?', pathParams: [ 'chainId' as const, 'id' as const ], - endpoint: appConfig.adminServiceApi.endpoint, - basePath: appConfig.adminServiceApi.basePath, + endpoint: config.features.addressVerification.api.endpoint, + basePath: config.features.addressVerification.api.basePath, needAuth: true, }, // STATS stats_counters: { path: '/api/v1/counters', - endpoint: appConfig.statsApi.endpoint, - basePath: appConfig.statsApi.basePath, + endpoint: config.features.stats.api.endpoint, + basePath: config.features.stats.api.basePath, }, stats_lines: { path: '/api/v1/lines', - endpoint: appConfig.statsApi.endpoint, - basePath: appConfig.statsApi.basePath, + endpoint: config.features.stats.api.endpoint, + basePath: config.features.stats.api.basePath, }, stats_line: { path: '/api/v1/lines/:id', pathParams: [ 'id' as const ], - endpoint: appConfig.statsApi.endpoint, - basePath: appConfig.statsApi.basePath, + endpoint: config.features.stats.api.endpoint, + basePath: config.features.stats.api.basePath, }, // VISUALIZATION visualize_sol2uml: { path: '/api/v1/solidity\\:visualize-contracts', - endpoint: appConfig.visualizeApi.endpoint, - basePath: appConfig.visualizeApi.basePath, + endpoint: config.features.sol2uml.api.endpoint, + basePath: config.features.sol2uml.api.basePath, }, // BLOCKS, TXS @@ -345,8 +345,8 @@ export const RESOURCES = { token_verified_info: { path: '/api/v1/chains/:chainId/token-infos/:hash', pathParams: [ 'chainId' as const, 'hash' as const ], - endpoint: appConfig.contractInfoApi.endpoint, - basePath: appConfig.contractInfoApi.basePath, + endpoint: config.features.verifiedTokens.api.endpoint, + basePath: config.features.verifiedTokens.api.basePath, }, token_counters: { path: '/api/v2/tokens/:hash/counters', diff --git a/lib/api/useApiFetch.tsx b/lib/api/useApiFetch.tsx index e55f78344a..453f3dc753 100644 --- a/lib/api/useApiFetch.tsx +++ b/lib/api/useApiFetch.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { CsrfData } from 'types/client/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import isBodyAllowed from 'lib/api/isBodyAllowed'; import isNeedProxy from 'lib/api/isNeedProxy'; import { getResourceKey } from 'lib/api/useApiQuery'; @@ -49,7 +49,7 @@ export default function useApiFetch() { // for user authentication in My account // for API rate-limits (cannot use in the condition though, but we agreed with devops team that should not be an issue) // change condition here if something is changed - credentials: appConfig.account.isEnabled ? 'include' : 'same-origin', + credentials: config.features.account.isEnabled ? 'include' : 'same-origin', headers, ...fetchParams, }, diff --git a/lib/csp/policies/app.ts b/lib/csp/policies/app.ts index 94689aa024..924d1d20c7 100644 --- a/lib/csp/policies/app.ts +++ b/lib/csp/policies/app.ts @@ -1,16 +1,15 @@ import type CspDev from 'csp-dev'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { KEY_WORDS } from '../utils'; const MAIN_DOMAINS = [ - `*.${ appConfig.app.host }`, - appConfig.app.host, - appConfig.visualizeApi.endpoint, + `*.${ config.app.host }`, + config.app.host, + config.features.sol2uml.api.endpoint, ].filter(Boolean); // eslint-disable-next-line no-restricted-properties -const REPORT_URI = process.env.SENTRY_CSP_REPORT_URI; export function app(): CspDev.DirectiveDescriptor { return { @@ -26,18 +25,18 @@ export function app(): CspDev.DirectiveDescriptor { ...MAIN_DOMAINS, // webpack hmr in safari doesn't recognize localhost as 'self' for some reason - appConfig.isDev ? 'ws://localhost:3000/_next/webpack-hmr' : '', + config.app.isDev ? 'ws://localhost:3000/_next/webpack-hmr' : '', - // API - appConfig.api.endpoint, - appConfig.api.socket, - appConfig.statsApi.endpoint, - appConfig.visualizeApi.endpoint, - appConfig.contractInfoApi.endpoint, - appConfig.adminServiceApi.endpoint, + // APIs + config.api.endpoint, + config.api.socket, + config.features.stats.api.endpoint, + config.features.sol2uml.api.endpoint, + config.features.verifiedTokens.api.endpoint, + config.features.addressVerification.api.endpoint, // chain RPC server - appConfig.network.rpcUrl, + config.chain.rpcUrl, 'https://infragrid.v.network', // RPC providers // github (spec for api-docs page) @@ -50,7 +49,7 @@ export function app(): CspDev.DirectiveDescriptor { // next.js generates and rebuilds source maps in dev using eval() // https://github.com/vercel/next.js/issues/14221#issuecomment-657258278 - appConfig.isDev ? KEY_WORDS.UNSAFE_EVAL : '', + config.app.isDev ? KEY_WORDS.UNSAFE_EVAL : '', // hash of ColorModeScript '\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'', @@ -109,9 +108,9 @@ export function app(): CspDev.DirectiveDescriptor { '*', ], - ...(REPORT_URI && !appConfig.isDev ? { + ...(config.features.sentry.isEnabled && config.features.sentry.cspReportUrl && !config.app.isDev ? { 'report-uri': [ - REPORT_URI, + config.features.sentry.cspReportUrl, ], } : {}), }; diff --git a/lib/csp/policies/googleAnalytics.ts b/lib/csp/policies/googleAnalytics.ts index dd42e20445..437d2c527c 100644 --- a/lib/csp/policies/googleAnalytics.ts +++ b/lib/csp/policies/googleAnalytics.ts @@ -1,9 +1,9 @@ import type CspDev from 'csp-dev'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export function googleAnalytics(): CspDev.DirectiveDescriptor { - if (!appConfig.googleAnalytics.propertyId) { + if (!config.features.googleAnalytics.isEnabled) { return {}; } diff --git a/lib/csp/policies/googleReCaptcha.ts b/lib/csp/policies/googleReCaptcha.ts index b3ea013464..d759e70d59 100644 --- a/lib/csp/policies/googleReCaptcha.ts +++ b/lib/csp/policies/googleReCaptcha.ts @@ -1,9 +1,9 @@ import type CspDev from 'csp-dev'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export function googleReCaptcha(): CspDev.DirectiveDescriptor { - if (!appConfig.reCaptcha.siteKey) { + if (!config.services.reCaptcha.siteKey) { return {}; } diff --git a/lib/csp/policies/mixpanel.ts b/lib/csp/policies/mixpanel.ts index 8cb8f944cf..0e2d8fee31 100644 --- a/lib/csp/policies/mixpanel.ts +++ b/lib/csp/policies/mixpanel.ts @@ -1,9 +1,9 @@ import type CspDev from 'csp-dev'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export function mixpanel(): CspDev.DirectiveDescriptor { - if (!appConfig.mixpanel.projectToken) { + if (!config.features.mixpanel.isEnabled) { return {}; } diff --git a/lib/csp/policies/walletConnect.ts b/lib/csp/policies/walletConnect.ts index 27823fbadd..7dcff73b87 100644 --- a/lib/csp/policies/walletConnect.ts +++ b/lib/csp/policies/walletConnect.ts @@ -1,9 +1,9 @@ import type CspDev from 'csp-dev'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export function walletConnect(): CspDev.DirectiveDescriptor { - if (!appConfig.walletConnect.projectId || !appConfig.network.rpcUrl) { + if (!config.features.blockchainInteraction.isEnabled) { return {}; } diff --git a/lib/hooks/useHasAccount.ts b/lib/hooks/useHasAccount.ts index d78a1a971b..d314f6f36a 100644 --- a/lib/hooks/useHasAccount.ts +++ b/lib/hooks/useHasAccount.ts @@ -1,11 +1,11 @@ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { useAppContext } from 'lib/contexts/app'; import * as cookies from 'lib/cookies'; export default function useHasAccount() { const appProps = useAppContext(); - if (!appConfig.account.isEnabled) { + if (!config.features.account.isEnabled) { return false; } diff --git a/lib/hooks/useIssueUrl.tsx b/lib/hooks/useIssueUrl.tsx index 81f0c76332..b0b74d8332 100644 --- a/lib/hooks/useIssueUrl.tsx +++ b/lib/hooks/useIssueUrl.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import isBrowser from 'lib/isBrowser'; const base = 'https://github.com/blockscout/blockscout/issues/new/'; const labels = 'new UI'; -const title = `${ appConfig.network.name }: `; +const title = `${ config.chain.name }: `; export default function useIssueUrl(backendVersion: string | undefined) { const [ userAgent, setUserAgent ] = React.useState(''); @@ -24,7 +24,7 @@ export default function useIssueUrl(backendVersion: string | undefined) { ### Environment * Backend Version/branch/commit: ${ backendVersion } -* Frontend Version+commit: ${ [ appConfig.footer.frontendVersion, appConfig.footer.frontendCommit ].filter(Boolean).join('+') } +* Frontend Version+commit: ${ [ config.UI.footer.frontendVersion, config.UI.footer.frontendCommit ].filter(Boolean).join('+') } * User Agent: ${ userAgent } ### Steps to reproduce diff --git a/lib/hooks/useLoginUrl.tsx b/lib/hooks/useLoginUrl.tsx index e1e41d0172..2f66b17640 100644 --- a/lib/hooks/useLoginUrl.tsx +++ b/lib/hooks/useLoginUrl.tsx @@ -1,9 +1,9 @@ import { useRouter } from 'next/router'; import { route } from 'nextjs-routes'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export default function useLoginUrl() { const router = useRouter(); - return appConfig.account.authUrl + route({ pathname: '/auth/auth0', query: { path: router.asPath } }); + return config.features.account.authUrl + route({ pathname: '/auth/auth0', query: { path: router.asPath } }); } diff --git a/lib/hooks/useNavItems.tsx b/lib/hooks/useNavItems.tsx index d5b124c841..1533f5356d 100644 --- a/lib/hooks/useNavItems.tsx +++ b/lib/hooks/useNavItems.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import abiIcon from 'icons/ABI.svg'; import apiKeysIcon from 'icons/API.svg'; import appsIcon from 'icons/apps.svg'; @@ -43,9 +43,6 @@ export function isInternalItem(item: NavItem): item is NavItemInternal { } export default function useNavItems(): ReturnType { - const isMarketplaceAvailable = Boolean(appConfig.marketplace.configUrl && appConfig.network.rpcUrl); - const hasAPIDocs = appConfig.apiDoc.specUrl; - const router = useRouter(); const pathname = router.pathname; @@ -74,7 +71,7 @@ export default function useNavItems(): ReturnType { // eslint-disable-next-line max-len { text: 'Verified contracts', nextRoute: { pathname: '/verified-contracts' as const }, icon: verifiedIcon, isActive: pathname === '/verified-contracts' }; - if (appConfig.L2.isL2Network) { + if (config.features.rollup.isEnabled) { blockchainNavItems = [ [ txs, @@ -101,7 +98,7 @@ export default function useNavItems(): ReturnType { blocks, topAccounts, verifiedContracts, - appConfig.beaconChain.hasBeaconChain && { + config.features.beaconChain.isEnabled && { text: 'Withdrawals', nextRoute: { pathname: '/withdrawals' as const }, icon: withdrawalsIcon, @@ -111,18 +108,18 @@ export default function useNavItems(): ReturnType { } const apiNavItems: Array = [ - hasAPIDocs ? { + config.features.restApiDocs.isEnabled ? { text: 'REST API', nextRoute: { pathname: '/api-docs' as const }, icon: apiDocsIcon, isActive: pathname === '/api-docs', } : null, - { + config.features.graphqlApiDocs.isEnabled ? { text: 'GraphQL', nextRoute: { pathname: '/graphiql' as const }, icon: graphQLIcon, isActive: pathname === '/graphiql', - }, + } : null, { text: 'RPC API', icon: rpcIcon, @@ -148,13 +145,13 @@ export default function useNavItems(): ReturnType { icon: tokensIcon, isActive: pathname.startsWith('/token'), }, - isMarketplaceAvailable ? { + config.features.marketplace.isEnabled ? { text: 'Apps', nextRoute: { pathname: '/apps' as const }, icon: appsIcon, isActive: pathname.startsWith('/app'), } : null, - appConfig.statsApi.endpoint ? { + config.features.stats.isEnabled ? { text: 'Charts & stats', nextRoute: { pathname: '/stats' as const }, icon: statsIcon, @@ -166,10 +163,10 @@ export default function useNavItems(): ReturnType { isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive), subItems: apiNavItems, }, - appConfig.navigation.otherLinks.length > 0 ? { + config.UI.sidebar.otherLinks.length > 0 ? { text: 'Other', icon: gearIcon, - subItems: appConfig.navigation.otherLinks, + subItems: config.UI.sidebar.otherLinks, } : null, ].filter(Boolean); @@ -202,7 +199,7 @@ export default function useNavItems(): ReturnType { icon: abiIcon, isActive: pathname === '/account/custom-abi', }, - appConfig.contractInfoApi.endpoint && appConfig.adminServiceApi.endpoint && { + config.features.addressVerification.isEnabled && { text: 'Verified addrs', nextRoute: { pathname: '/account/verified-addresses' as const }, icon: verifiedIcon, @@ -218,5 +215,5 @@ export default function useNavItems(): ReturnType { }; return { mainNavItems, accountNavItems, profileItem }; - }, [ hasAPIDocs, isMarketplaceAvailable, pathname ]); + }, [ pathname ]); } diff --git a/lib/metadata/generate.ts b/lib/metadata/generate.ts index f3c9e452fb..2d938b95d5 100644 --- a/lib/metadata/generate.ts +++ b/lib/metadata/generate.ts @@ -2,7 +2,7 @@ import type { Route } from 'nextjs-routes'; import type { ApiData, Metadata } from './types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import getNetworkTitle from 'lib/networks/getNetworkTitle'; import compileValue from './compileValue'; @@ -12,7 +12,7 @@ export default function generate(route: R, apiData?: ApiData const params = { ...route.query, ...apiData, - network_name: appConfig.network.name, + network_name: config.chain.name, network_title: getNetworkTitle(), }; diff --git a/lib/mixpanel/isGoogleAnalyticsLoaded.ts b/lib/mixpanel/isGoogleAnalyticsLoaded.ts index 54366e4279..08667749b1 100644 --- a/lib/mixpanel/isGoogleAnalyticsLoaded.ts +++ b/lib/mixpanel/isGoogleAnalyticsLoaded.ts @@ -1,8 +1,8 @@ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import delay from 'lib/delay'; export default function isGoogleAnalyticsLoaded(retries = 3): Promise { - if (!retries || !appConfig.googleAnalytics.propertyId) { + if (!retries || !config.features.googleAnalytics.isEnabled) { return Promise.resolve(false); } return typeof window.ga?.getAll === 'function' ? Promise.resolve(true) : delay(500).then(() => isGoogleAnalyticsLoaded(retries - 1)); diff --git a/lib/mixpanel/logEvent.ts b/lib/mixpanel/logEvent.ts index 50ae085e16..8a001351ea 100644 --- a/lib/mixpanel/logEvent.ts +++ b/lib/mixpanel/logEvent.ts @@ -1,6 +1,6 @@ import mixpanel from 'mixpanel-browser'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import type { EventTypes, EventPayload } from './utils'; @@ -12,7 +12,7 @@ export default function logEvent( optionsOrCallback?: TrackFnArgs[2], callback?: TrackFnArgs[3], ) { - if (!appConfig.mixpanel.projectToken) { + if (!config.features.mixpanel.isEnabled) { return; } mixpanel.track(type, properties, optionsOrCallback, callback); diff --git a/lib/mixpanel/useInit.tsx b/lib/mixpanel/useInit.tsx index 460cfe3d3a..bd0dd26150 100644 --- a/lib/mixpanel/useInit.tsx +++ b/lib/mixpanel/useInit.tsx @@ -5,7 +5,7 @@ import { useRouter } from 'next/router'; import React from 'react'; import { deviceType } from 'react-device-detect'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import * as cookies from 'lib/cookies'; import getQueryParamString from 'lib/router/getQueryParamString'; @@ -19,21 +19,21 @@ export default function useMixpanelInit() { React.useEffect(() => { isGoogleAnalyticsLoaded().then((isGALoaded) => { - if (!appConfig.mixpanel.projectToken) { + if (!config.features.mixpanel.isEnabled) { return; } const debugFlagCookie = cookies.get(cookies.NAMES.MIXPANEL_DEBUG); - const config: Partial = { + const mixpanelConfig: Partial = { debug: Boolean(debugFlagQuery.current || debugFlagCookie), }; const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN)); - mixpanel.init(appConfig.mixpanel.projectToken, config); + mixpanel.init(config.features.mixpanel.projectToken, mixpanelConfig); mixpanel.register({ - 'Chain id': appConfig.network.id, - Environment: appConfig.isDev ? 'Dev' : 'Prod', + 'Chain id': config.chain.id, + Environment: config.app.isDev ? 'Dev' : 'Prod', Authorized: isAuth, 'Viewport width': window.innerWidth, 'Viewport height': window.innerHeight, diff --git a/lib/mixpanel/useLogPageView.tsx b/lib/mixpanel/useLogPageView.tsx index 1c2d41a69a..04c25de7ec 100644 --- a/lib/mixpanel/useLogPageView.tsx +++ b/lib/mixpanel/useLogPageView.tsx @@ -2,7 +2,7 @@ import { usePathname } from 'next/navigation'; import { useRouter } from 'next/router'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import getQueryParamString from 'lib/router/getQueryParamString'; import getPageType from './getPageType'; @@ -18,7 +18,7 @@ export default function useLogPageView(isInited: boolean) { const page = getQueryParamString(router.query.page); React.useEffect(() => { - if (!appConfig.mixpanel.projectToken || !isInited) { + if (!config.features.mixpanel.isEnabled || !isInited) { return; } diff --git a/lib/networks/getNetworkTitle.ts b/lib/networks/getNetworkTitle.ts index 749041b360..5bcb602e39 100644 --- a/lib/networks/getNetworkTitle.ts +++ b/lib/networks/getNetworkTitle.ts @@ -1,6 +1,6 @@ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; // TODO delete when page descriptions is refactored export default function getNetworkTitle() { - return appConfig.network.name + (appConfig.network.shortName ? ` (${ appConfig.network.shortName })` : '') + ' Explorer'; + return config.chain.name + (config.chain.shortName ? ` (${ config.chain.shortName })` : '') + ' Explorer'; } diff --git a/lib/networks/getNetworkValidatorTitle.ts b/lib/networks/getNetworkValidatorTitle.ts index 886f7229de..7435ee0293 100644 --- a/lib/networks/getNetworkValidatorTitle.ts +++ b/lib/networks/getNetworkValidatorTitle.ts @@ -1,5 +1,5 @@ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export default function getNetworkValidatorTitle() { - return appConfig.network.verificationType === 'validation' ? 'validator' : 'miner'; + return config.chain.verificationType === 'validation' ? 'validator' : 'miner'; } diff --git a/lib/networks/networkExplorers.ts b/lib/networks/networkExplorers.ts index febc2054ac..cfcc828115 100644 --- a/lib/networks/networkExplorers.ts +++ b/lib/networks/networkExplorers.ts @@ -3,7 +3,7 @@ import _mapValues from 'lodash/mapValues'; import type { NetworkExplorer } from 'types/networks'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; // for easy .env update // const NETWORK_EXPLORERS = JSON.stringify([ @@ -29,7 +29,7 @@ const stripTrailingSlash = (str: string) => str[str.length - 1] === '/' ? str.sl const addLeadingSlash = (str: string) => str[0] === '/' ? str : '/' + str; const networkExplorers: Array = (() => { - return appConfig.network.explorers.map((explorer) => ({ + return config.UI.explorers.items.map((explorer) => ({ ...explorer, baseUrl: stripTrailingSlash(explorer.baseUrl), paths: _mapValues(explorer.paths, _compose(stripTrailingSlash, addLeadingSlash)), diff --git a/lib/next/getServerSideProps.ts b/lib/next/getServerSideProps.ts index aa054ccf32..48021b5614 100644 --- a/lib/next/getServerSideProps.ts +++ b/lib/next/getServerSideProps.ts @@ -1,6 +1,6 @@ import type { GetServerSideProps } from 'next'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export type Props = { cookies: string; @@ -25,7 +25,7 @@ export const base: GetServerSideProps = async({ req, query }) => { }; export const account: GetServerSideProps = async(context) => { - if (!appConfig.account.isEnabled) { + if (!config.features.account.isEnabled) { return { notFound: true, }; @@ -35,7 +35,7 @@ export const account: GetServerSideProps = async(context) => { }; export const verifiedAddresses: GetServerSideProps = async(context) => { - if (!appConfig.adminServiceApi.endpoint || !appConfig.contractInfoApi.endpoint) { + if (!config.features.addressVerification.isEnabled) { return { notFound: true, }; @@ -45,7 +45,7 @@ export const verifiedAddresses: GetServerSideProps = async(context) => { }; export const beaconChain: GetServerSideProps = async(context) => { - if (!appConfig.beaconChain.hasBeaconChain) { + if (!config.features.beaconChain.isEnabled) { return { notFound: true, }; @@ -55,7 +55,7 @@ export const beaconChain: GetServerSideProps = async(context) => { }; export const L2: GetServerSideProps = async(context) => { - if (!appConfig.L2.isL2Network) { + if (!config.features.rollup.isEnabled) { return { notFound: true, }; @@ -65,7 +65,7 @@ export const L2: GetServerSideProps = async(context) => { }; export const marketplace: GetServerSideProps = async(context) => { - if (!appConfig.marketplace.configUrl || !appConfig.network.rpcUrl) { + if (!config.features.marketplace.isEnabled) { return { notFound: true, }; @@ -75,7 +75,7 @@ export const marketplace: GetServerSideProps = async(context) => { }; export const apiDocs: GetServerSideProps = async(context) => { - if (!appConfig.apiDoc.specUrl) { + if (!config.features.restApiDocs.isEnabled) { return { notFound: true, }; @@ -85,7 +85,7 @@ export const apiDocs: GetServerSideProps = async(context) => { }; export const csvExport: GetServerSideProps = async(context) => { - if (!appConfig.reCaptcha.siteKey) { + if (!config.features.csvExport.isEnabled) { return { notFound: true, }; @@ -95,7 +95,7 @@ export const csvExport: GetServerSideProps = async(context) => { }; export const stats: GetServerSideProps = async(context) => { - if (!appConfig.statsApi.endpoint) { + if (!config.features.stats.isEnabled) { return { notFound: true, }; diff --git a/lib/next/middlewares/account.ts b/lib/next/middlewares/account.ts index 7152971f03..000e47e311 100644 --- a/lib/next/middlewares/account.ts +++ b/lib/next/middlewares/account.ts @@ -2,13 +2,13 @@ import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; import { route } from 'nextjs-routes'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { httpLogger } from 'lib/api/logger'; import { DAY } from 'lib/consts'; import * as cookies from 'lib/cookies'; export function account(req: NextRequest) { - if (!appConfig.account.isEnabled) { + if (!config.features.account.isEnabled) { return; } @@ -24,7 +24,7 @@ export function account(req: NextRequest) { const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile'); if ((isAccountRoute || isProfileRoute)) { - const authUrl = appConfig.account.authUrl + route({ pathname: '/auth/auth0', query: { path: req.nextUrl.pathname } }); + const authUrl = config.features.account.authUrl + route({ pathname: '/auth/auth0', query: { path: req.nextUrl.pathname } }); return NextResponse.redirect(authUrl); } } @@ -35,7 +35,7 @@ export function account(req: NextRequest) { if (apiTokenCookie) { // temporary solution // TODO check app for integrity https://github.com/blockscout/frontend/issues/1028 and make typescript happy here - if (!appConfig.account.logoutUrl) { + if (!config.features.account.logoutUrl) { httpLogger.logger.error({ message: 'Logout URL is not configured', }); @@ -46,7 +46,7 @@ export function account(req: NextRequest) { // logout URL is always external URL in auth0.com sub-domain // at least we hope so - const res = NextResponse.redirect(appConfig.account.logoutUrl); + const res = NextResponse.redirect(config.features.account.logoutUrl); res.cookies.delete(cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED); // reset cookie to show email verification page again return res; @@ -55,7 +55,7 @@ export function account(req: NextRequest) { // if user hasn't seen email verification page, make redirect to it if (!req.cookies.get(cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED)) { if (!req.nextUrl.pathname.includes('/auth/unverified-email')) { - const url = appConfig.app.baseUrl + route({ pathname: '/auth/unverified-email' }); + const url = config.app.baseUrl + route({ pathname: '/auth/unverified-email' }); const res = NextResponse.redirect(url); res.cookies.set({ name: cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED, diff --git a/lib/web3/useProvider.tsx b/lib/web3/useProvider.tsx index a12e446e22..6e508e22e2 100644 --- a/lib/web3/useProvider.tsx +++ b/lib/web3/useProvider.tsx @@ -3,13 +3,13 @@ import type { WindowProvider } from 'wagmi'; import 'wagmi/window'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export default function useProvider() { const [ provider, setProvider ] = React.useState(); React.useEffect(() => { - if (!('ethereum' in window && window.ethereum)) { + if (!('ethereum' in window && window.ethereum) || !config.features.web3Wallet.isEnabled) { return; } @@ -18,11 +18,11 @@ export default function useProvider() { const providers = Array.isArray(window.ethereum.providers) ? window.ethereum.providers : [ window.ethereum ]; providers.forEach(async(provider) => { - if (appConfig.web3.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) { + if (config.features.web3Wallet.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) { return setProvider(provider); } - if (appConfig.web3.defaultWallet === 'metamask' && provider.isMetaMask) { + if (config.features.web3Wallet.defaultWallet === 'metamask' && provider.isMetaMask) { return setProvider(provider); } }); diff --git a/lib/web3/wallets.ts b/lib/web3/wallets.ts index db79f4331a..241c3fce0e 100644 --- a/lib/web3/wallets.ts +++ b/lib/web3/wallets.ts @@ -3,7 +3,7 @@ import type { WalletType, WalletInfo } from 'types/client/wallets'; import coinbaseIcon from 'icons/wallets/coinbase.svg'; import metamaskIcon from 'icons/wallets/metamask.svg'; -export const WALLETS_INFO: Record = { +export const WALLETS_INFO: Record, WalletInfo> = { metamask: { name: 'MetaMask', icon: metamaskIcon, diff --git a/pages/_app.tsx b/pages/_app.tsx index 79269f938a..eeb067d7d0 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -5,7 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import type { AppProps } from 'next/app'; import React, { useState } from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { AppContextProvider } from 'lib/contexts/app'; import { ChakraProvider } from 'lib/contexts/chakra'; import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection'; @@ -85,7 +85,7 @@ function MyApp({ Component, pageProps }: AppProps) { - + diff --git a/pages/_document.tsx b/pages/_document.tsx index f016459605..a7db5d1fb1 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -3,7 +3,7 @@ import type { DocumentContext } from 'next/document'; import Document, { Html, Head, Main, NextScript } from 'next/document'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import * as serverTiming from 'lib/next/serverTiming'; import theme from 'theme'; @@ -47,11 +47,11 @@ class MyDocument extends Document { // eslint-disable-next-line max-len content="Blockscout is the #1 open-source blockchain explorer available today. 100+ chains and counting rely on Blockscout data availability, APIs, and ecosystem tools to support their networks." /> - + - + diff --git a/pages/api/proxy.ts b/pages/api/proxy.ts index 3e30983f10..6df18da88f 100644 --- a/pages/api/proxy.ts +++ b/pages/api/proxy.ts @@ -2,7 +2,7 @@ import _pick from 'lodash/pick'; import _pickBy from 'lodash/pickBy'; import type { NextApiRequest, NextApiResponse } from 'next'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import fetchFactory from 'lib/api/nodeFetch'; const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => { @@ -13,7 +13,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => { const url = new URL( nextReq.url.replace(/^\/node-api\/proxy/, ''), - nextReq.headers['x-endpoint']?.toString() || appConfig.api.endpoint, + nextReq.headers['x-endpoint']?.toString() || config.api.endpoint, ); const apiRes = await fetchFactory(nextReq)( url.toString(), diff --git a/types/client/wallets.ts b/types/client/wallets.ts index 902cdfe878..3c2ba26278 100644 --- a/types/client/wallets.ts +++ b/types/client/wallets.ts @@ -1,4 +1,4 @@ -export type WalletType = 'metamask' | 'coinbase'; +export type WalletType = 'metamask' | 'coinbase' | 'none'; export interface WalletInfo { name: string; diff --git a/types/envs.ts b/types/envs.ts index 9b12f5e5e1..0ef9b7f4e5 100644 --- a/types/envs.ts +++ b/types/envs.ts @@ -7,7 +7,6 @@ export type NextPublicEnvs = { NEXT_PUBLIC_NETWORK_CURRENCY_NAME?: string; NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL?: string; NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS?: string; - NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS?: string; NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME?: string; NEXT_PUBLIC_NETWORK_LOGO?: string; NEXT_PUBLIC_NETWORK_LOGO_DARK?: string; @@ -34,18 +33,13 @@ export type NextPublicEnvs = { NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER?: 'true' | 'false'; NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME?: 'true' | 'false'; - // Ads config - NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP?: string; - NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE?: string; - NEXT_PUBLIC_AD_BANNER_PROVIDER?: 'slise' | 'adbutler' | 'coinzilla' | 'none'; + // Text ads config NEXT_PUBLIC_AD_TEXT_PROVIDER?: 'coinzilla' | 'none'; // App config - NEXT_PUBLIC_APP_INSTANCE?: string; NEXT_PUBLIC_APP_PROTOCOL?: 'http' | 'https'; NEXT_PUBLIC_APP_HOST: string; NEXT_PUBLIC_APP_PORT?: string; - NEXT_PUBLIC_APP_ENV?: string; // API config NEXT_PUBLIC_API_PROTOCOL?: 'http' | 'https'; @@ -56,11 +50,8 @@ export type NextPublicEnvs = { NEXT_PUBLIC_STATS_API_HOST?: string; NEXT_PUBLIC_VISUALIZE_API_HOST?: string; NEXT_PUBLIC_CONTRACT_INFO_API_HOST?: string; - NEXT_PUBLIC_ADMIN_SERVICE_API_HOST?: string; // external services config - NEXT_PUBLIC_SENTRY_DSN?: string; - SENTRY_CSP_REPORT_URI?: string; NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID?: string; NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY?: string; NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID?: string; @@ -73,7 +64,9 @@ export type NextPublicEnvs = { & NextPublicEnvsAccount & NextPublicEnvsMarketplace & NextPublicEnvsRollup -& NextPublicEnvsBeacon; +& NextPublicEnvsBeacon +& NextPublicEnvsAdsBanner +& NextPublicEnvsSentry; type NextPublicEnvsAccount = { @@ -87,6 +80,7 @@ type NextPublicEnvsAccount = NEXT_PUBLIC_AUTH_URL?: string; NEXT_PUBLIC_LOGOUT_URL: string; NEXT_PUBLIC_AUTH0_CLIENT_ID: string; + NEXT_PUBLIC_ADMIN_SERVICE_API_HOST?: string; } type NextPublicEnvsMarketplace = @@ -120,3 +114,30 @@ type NextPublicEnvsBeacon = NEXT_PUBLIC_HAS_BEACON_CHAIN?: undefined; NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL?: undefined; } + +type NextPublicEnvsAdsBanner = +{ + NEXT_PUBLIC_AD_BANNER_PROVIDER: 'slise' | 'coinzilla' | 'none'; +} | +{ + NEXT_PUBLIC_AD_BANNER_PROVIDER: 'adbutler'; + NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP: string; + NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: string; +} | +{ + NEXT_PUBLIC_AD_BANNER_PROVIDER?: undefined; +} + +type NextPublicEnvsSentry = +{ + NEXT_PUBLIC_SENTRY_DSN: string; + SENTRY_CSP_REPORT_URI?: string; + NEXT_PUBLIC_APP_INSTANCE?: string; + NEXT_PUBLIC_APP_ENV?: string; +} | +{ + NEXT_PUBLIC_SENTRY_DSN?: undefined; + SENTRY_CSP_REPORT_URI?: undefined; + NEXT_PUBLIC_APP_INSTANCE?: undefined; + NEXT_PUBLIC_APP_ENV?: undefined; +} diff --git a/ui/address/AddressBlocksValidated.tsx b/ui/address/AddressBlocksValidated.tsx index 547edc7547..f52b484f05 100644 --- a/ui/address/AddressBlocksValidated.tsx +++ b/ui/address/AddressBlocksValidated.tsx @@ -6,7 +6,7 @@ import React from 'react'; import type { SocketMessage } from 'lib/socket/types'; import type { AddressBlocksValidatedResponse } from 'types/api/address'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { getResourceKey } from 'lib/api/useApiQuery'; import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketMessage from 'lib/socket/useSocketMessage'; @@ -94,7 +94,7 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => { Age Txn Gas used - Reward { appConfig.network.currency.symbol } + Reward { config.chain.currency.symbol } diff --git a/ui/address/AddressCsvExportLink.tsx b/ui/address/AddressCsvExportLink.tsx index 34c01b0165..70b179e471 100644 --- a/ui/address/AddressCsvExportLink.tsx +++ b/ui/address/AddressCsvExportLink.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { CsvExportParams } from 'types/client/address'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import svgFileIcon from 'icons/files/csv.svg'; import useIsInitialLoading from 'lib/hooks/useIsInitialLoading'; import useIsMobile from 'lib/hooks/useIsMobile'; @@ -21,7 +21,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props) const isMobile = useIsMobile(); const isInitialLoading = useIsInitialLoading(isLoading); - if (!appConfig.reCaptcha.siteKey) { + if (!config.features.csvExport.isEnabled) { return null; } diff --git a/ui/address/blocksValidated/AddressBlocksValidatedListItem.tsx b/ui/address/blocksValidated/AddressBlocksValidatedListItem.tsx index 7bfbfe0f0d..451cfb221b 100644 --- a/ui/address/blocksValidated/AddressBlocksValidatedListItem.tsx +++ b/ui/address/blocksValidated/AddressBlocksValidatedListItem.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import LinkInternal from 'ui/shared/LinkInternal'; @@ -48,7 +48,7 @@ const AddressBlocksValidatedListItem = (props: Props) => { /> - Reward { appConfig.network.currency.symbol } + Reward { config.chain.currency.symbol } { totalReward.toFixed() } diff --git a/ui/address/coinBalance/AddressCoinBalanceChart.tsx b/ui/address/coinBalance/AddressCoinBalanceChart.tsx index 3893383b67..8d55091a1d 100644 --- a/ui/address/coinBalance/AddressCoinBalanceChart.tsx +++ b/ui/address/coinBalance/AddressCoinBalanceChart.tsx @@ -1,7 +1,7 @@ import BigNumber from 'bignumber.js'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import ChartWidget from 'ui/shared/chart/ChartWidget'; @@ -16,7 +16,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => { const items = React.useMemo(() => data?.map(({ date, value }) => ({ date: new Date(date), - value: BigNumber(value).div(10 ** appConfig.network.currency.decimals).toNumber(), + value: BigNumber(value).div(10 ** config.chain.currency.decimals).toNumber(), })), [ data ]); return ( @@ -26,7 +26,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => { items={ items } isLoading={ isLoading } h="300px" - units={ appConfig.network.currency.symbol } + units={ config.chain.currency.symbol } /> ); }; diff --git a/ui/address/coinBalance/AddressCoinBalanceHistory.tsx b/ui/address/coinBalance/AddressCoinBalanceHistory.tsx index 4692457074..8b491093ed 100644 --- a/ui/address/coinBalance/AddressCoinBalanceHistory.tsx +++ b/ui/address/coinBalance/AddressCoinBalanceHistory.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { AddressCoinBalanceHistoryResponse } from 'types/api/address'; import type { PaginationParams } from 'ui/shared/pagination/types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import ActionBar from 'ui/shared/ActionBar'; import DataListDisplay from 'ui/shared/DataListDisplay'; import Pagination from 'ui/shared/pagination/Pagination'; @@ -31,7 +31,7 @@ const AddressCoinBalanceHistory = ({ query }: Props) => { Block Txn Age - Balance { appConfig.network.currency.symbol } + Balance { config.chain.currency.symbol } Delta diff --git a/ui/address/coinBalance/AddressCoinBalanceListItem.tsx b/ui/address/coinBalance/AddressCoinBalanceListItem.tsx index 48db11d74f..24014e1827 100644 --- a/ui/address/coinBalance/AddressCoinBalanceListItem.tsx +++ b/ui/address/coinBalance/AddressCoinBalanceListItem.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { AddressCoinBalanceHistoryItem } from 'types/api/address'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { WEI, ZERO } from 'lib/consts'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import Address from 'ui/shared/address/Address'; @@ -28,7 +28,7 @@ const AddressCoinBalanceListItem = (props: Props) => { - { BigNumber(props.value).div(WEI).dp(8).toFormat() } { appConfig.network.currency.symbol } + { BigNumber(props.value).div(WEI).dp(8).toFormat() } { config.chain.currency.symbol } diff --git a/ui/address/contract/ContractMethodConstant.tsx b/ui/address/contract/ContractMethodConstant.tsx index 7e12256fc1..5a0b10d28a 100644 --- a/ui/address/contract/ContractMethodConstant.tsx +++ b/ui/address/contract/ContractMethodConstant.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { SmartContractMethodOutput } from 'types/api/contract'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { WEI } from 'lib/consts'; import Address from 'ui/shared/address/Address'; import AddressLink from 'ui/shared/address/AddressLink'; @@ -39,7 +39,7 @@ const ContractMethodStatic = ({ data }: Props) => { if (event.target.checked) { setValue(BigNumber(initialValue).div(WEI).toFixed()); - setLabel(appConfig.network.currency.symbol || 'ETH'); + setLabel(config.chain.currency.symbol || 'ETH'); } else { setValue(BigNumber(initialValue).toFixed()); setLabel('WEI'); diff --git a/ui/address/contract/ContractMethodsAccordionItem.tsx b/ui/address/contract/ContractMethodsAccordionItem.tsx index 1d7c53243a..4f3a38d354 100644 --- a/ui/address/contract/ContractMethodsAccordionItem.tsx +++ b/ui/address/contract/ContractMethodsAccordionItem.tsx @@ -5,7 +5,7 @@ import { Element } from 'react-scroll'; import type { SmartContractMethod } from 'types/api/contract'; -import config from 'configs/app/config'; +import config from 'configs/app'; import iconLink from 'icons/link.svg'; import Hint from 'ui/shared/Hint'; diff --git a/ui/address/contract/ContractWrite.tsx b/ui/address/contract/ContractWrite.tsx index 7bb34d91f6..73c253ac71 100644 --- a/ui/address/contract/ContractWrite.tsx +++ b/ui/address/contract/ContractWrite.tsx @@ -3,7 +3,7 @@ import { useAccount, useWalletClient, useNetwork, useSwitchNetwork } from 'wagmi import type { SmartContractWriteMethod } from 'types/api/contract'; -import config from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import ContractMethodsAccordion from 'ui/address/contract/ContractMethodsAccordion'; import ContentLoader from 'ui/shared/ContentLoader'; @@ -46,8 +46,8 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => { throw new Error('Wallet is not connected'); } - if (chain?.id && String(chain.id) !== config.network.id) { - await switchNetworkAsync?.(Number(config.network.id)); + if (chain?.id && String(chain.id) !== config.chain.id) { + await switchNetworkAsync?.(Number(config.chain.id)); } if (!contractAbi) { diff --git a/ui/address/details/AddressBalance.tsx b/ui/address/details/AddressBalance.tsx index 6e3e666dca..401822684d 100644 --- a/ui/address/details/AddressBalance.tsx +++ b/ui/address/details/AddressBalance.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { SocketMessage } from 'lib/socket/types'; import type { Address } from 'types/api/address'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { getResourceKey } from 'lib/api/useApiQuery'; import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketMessage from 'lib/socket/useSocketMessage'; @@ -65,15 +65,14 @@ const AddressBalance = ({ data, isLoading }: Props) => { }); const tokenData = React.useMemo(() => ({ - address: appConfig.network.currency.address || '', - name: appConfig.network.currency.name || '', + name: config.chain.currency.name || '', icon_url: '', }), [ ]); return ( { - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } - { BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() } + { BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() } diff --git a/ui/address/internals/AddressIntTxsTable.tsx b/ui/address/internals/AddressIntTxsTable.tsx index 945d4957ae..e17bacb44f 100644 --- a/ui/address/internals/AddressIntTxsTable.tsx +++ b/ui/address/internals/AddressIntTxsTable.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { InternalTransaction } from 'types/api/internalTransaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { default as Thead } from 'ui/shared/TheadSticky'; import AddressIntTxsTableItem from './AddressIntTxsTableItem'; @@ -26,7 +26,7 @@ const AddressIntTxsTable = ({ data, currentAddress, isLoading }: Props) => { To - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } diff --git a/ui/address/internals/AddressIntTxsTableItem.tsx b/ui/address/internals/AddressIntTxsTableItem.tsx index a1bc472eb9..1fa8364071 100644 --- a/ui/address/internals/AddressIntTxsTableItem.tsx +++ b/ui/address/internals/AddressIntTxsTableItem.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { InternalTransaction } from 'types/api/internalTransaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import Address from 'ui/shared/address/Address'; @@ -105,7 +105,7 @@ const AddressIntTxsTableItem = ({ - { BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() } + { BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() } diff --git a/ui/address/tokens/TokenBalances.tsx b/ui/address/tokens/TokenBalances.tsx index b1c2582c84..890f8dc9b3 100644 --- a/ui/address/tokens/TokenBalances.tsx +++ b/ui/address/tokens/TokenBalances.tsx @@ -2,7 +2,7 @@ import { Flex } from '@chakra-ui/react'; import { useRouter } from 'next/router'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import { ZERO } from 'lib/consts'; import getCurrencyValue from 'lib/getCurrencyValue'; @@ -34,7 +34,7 @@ const TokenBalances = () => { accuracy: 8, accuracyUsd: 2, exchangeRate: addressData?.exchange_rate, - decimals: String(appConfig.network.currency.decimals), + decimals: String(config.chain.currency.decimals), }); const tokensInfo = getTokensTotalInfo(tokenQuery.data); @@ -52,8 +52,8 @@ const TokenBalances = () => { isLoading={ addressQuery.isLoading || tokenQuery.isLoading } /> ('address_verification', { fetchParams: { method: 'POST', body }, - pathParams: { chainId: appConfig.network.id, type: ':prepare' }, + pathParams: { chainId: config.chain.id, type: ':prepare' }, }); if (response.status !== 'SUCCESS') { diff --git a/ui/addressVerification/steps/AddressVerificationStepSignature.tsx b/ui/addressVerification/steps/AddressVerificationStepSignature.tsx index 0ec22b54c0..bb4c0bf9f4 100644 --- a/ui/addressVerification/steps/AddressVerificationStepSignature.tsx +++ b/ui/addressVerification/steps/AddressVerificationStepSignature.tsx @@ -15,7 +15,7 @@ import type { } from '../types'; import type { VerifiedAddress } from 'types/api/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiFetch from 'lib/api/useApiFetch'; import shortenString from 'lib/shortenString'; import CopyToClipboard from 'ui/shared/CopyToClipboard'; @@ -62,7 +62,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre const response = await apiFetch<'address_verification', AddressValidationResponseSuccess, AddressVerificationResponseError>('address_verification', { fetchParams: { method: 'POST', body }, - pathParams: { chainId: appConfig.network.id, type: ':verify' }, + pathParams: { chainId: config.chain.id, type: ':verify' }, }); if (response.status !== 'SUCCESS') { diff --git a/ui/addresses/AddressesListItem.tsx b/ui/addresses/AddressesListItem.tsx index 4ed91e75e8..7b0c59d762 100644 --- a/ui/addresses/AddressesListItem.tsx +++ b/ui/addresses/AddressesListItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { AddressesItem } from 'types/api/addresses'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import Address from 'ui/shared/address/Address'; import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressLink from 'ui/shared/address/AddressLink'; @@ -26,7 +26,7 @@ const AddressesListItem = ({ isLoading, }: Props) => { - const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** appConfig.network.currency.decimals)); + const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** config.chain.currency.decimals)); return ( @@ -52,7 +52,7 @@ const AddressesListItem = ({ { tag.display_name } )) } - { `Balance ${ appConfig.network.currency.symbol }` } + { `Balance ${ config.chain.currency.symbol }` } { addressBalance.dp(8).toFormat() } diff --git a/ui/addresses/AddressesTable.tsx b/ui/addresses/AddressesTable.tsx index 51cbb98fec..4a87862332 100644 --- a/ui/addresses/AddressesTable.tsx +++ b/ui/addresses/AddressesTable.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { AddressesItem } from 'types/api/addresses'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { default as Thead } from 'ui/shared/TheadSticky'; import AddressesTableItem from './AddressesTableItem'; @@ -25,7 +25,7 @@ const AddressesTable = ({ items, totalSupply, pageStartIndex, top, isLoading }: Rank Address Public tag - { `Balance ${ appConfig.network.currency.symbol }` } + { `Balance ${ config.chain.currency.symbol }` } { hasPercentage && Percentage } Txn count diff --git a/ui/addresses/AddressesTableItem.tsx b/ui/addresses/AddressesTableItem.tsx index 64e5401eb6..6cf06270d9 100644 --- a/ui/addresses/AddressesTableItem.tsx +++ b/ui/addresses/AddressesTableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { AddressesItem } from 'types/api/addresses'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import Address from 'ui/shared/address/Address'; import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressLink from 'ui/shared/address/AddressLink'; @@ -27,7 +27,7 @@ const AddressesTableItem = ({ isLoading, }: Props) => { - const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** appConfig.network.currency.decimals)); + const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** config.chain.currency.decimals)); const addressBalanceChunks = addressBalance.dp(8).toFormat().split('.'); return ( diff --git a/ui/apiDocs/SwaggerUI.tsx b/ui/apiDocs/SwaggerUI.tsx index 43e19f8f52..f60a13b324 100644 --- a/ui/apiDocs/SwaggerUI.tsx +++ b/ui/apiDocs/SwaggerUI.tsx @@ -8,7 +8,7 @@ import { Box, useColorModeValue } from '@chakra-ui/react'; import dynamic from 'next/dynamic'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import ContentLoader from 'ui/shared/ContentLoader'; import 'swagger-ui-react/swagger-ui.css'; @@ -57,7 +57,7 @@ const SwaggerUI = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const reqInterceptor = React.useCallback((req: any) => { if (!req.loadSpec) { - req.url = req.url.replace(DEFAULT_SERVER, appConfig.api.host); + req.url = req.url.replace(DEFAULT_SERVER, config.api.host); const url = new URL(req.url); url.protocol = 'https:'; req.url = url.toString(); @@ -68,7 +68,7 @@ const SwaggerUI = () => { return ( diff --git a/ui/block/BlockDetails.tsx b/ui/block/BlockDetails.tsx index e9c2489402..fb95a4213d 100644 --- a/ui/block/BlockDetails.tsx +++ b/ui/block/BlockDetails.tsx @@ -9,7 +9,7 @@ import { scroller, Element } from 'react-scroll'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import clockIcon from 'icons/clock.svg'; import flameIcon from 'icons/flame.svg'; import type { ResourceError } from 'lib/api/resources'; @@ -94,7 +94,7 @@ const BlockDetails = ({ query }: Props) => { const validatorTitle = getNetworkValidatorTitle(); const rewardBreakDown = (() => { - if (appConfig.L2.isL2Network || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) { + if (config.features.rollup.isEnabled || totalReward.isEqualTo(ZERO) || txFees.isEqualTo(ZERO) || burntFees.isEqualTo(ZERO)) { return null; } @@ -186,7 +186,7 @@ const BlockDetails = ({ query }: Props) => { - { appConfig.beaconChain.hasBeaconChain && Boolean(data.withdrawals_count) && ( + { config.features.beaconChain.isEnabled && Boolean(data.withdrawals_count) && ( { ) } { { /* api doesn't return the block processing time yet */ } { /* { dayjs.duration(block.minedIn, 'second').humanize(true) } */ } - { !appConfig.L2.isL2Network && !totalReward.isEqualTo(ZERO) && ( + { !config.features.rollup.isEnabled && !totalReward.isEqualTo(ZERO) && ( - { totalReward.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { totalReward.dividedBy(WEI).toFixed() } { config.chain.currency.symbol } { rewardBreakDown } @@ -235,7 +235,7 @@ const BlockDetails = ({ query }: Props) => { // is this text correct for validators? hint={ `Amount of distributed reward. ${ capitalize(validatorTitle) }s receive a static block reward + Tx fees + uncle fees` } > - { BigNumber(reward).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { BigNumber(reward).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } )) } @@ -293,7 +293,7 @@ const BlockDetails = ({ query }: Props) => { ) : ( <> - { BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { BigNumber(data.base_fee_per_gas).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } { space }({ BigNumber(data.base_fee_per_gas).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) @@ -304,7 +304,7 @@ const BlockDetails = ({ query }: Props) => { { > - { burntFees.dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { burntFees.dividedBy(WEI).toFixed() } { config.chain.currency.symbol } { !txFees.isEqualTo(ZERO) && ( @@ -333,7 +333,7 @@ const BlockDetails = ({ query }: Props) => { isLoading={ isPlaceholderData } > - { BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { BigNumber(data.priority_fee).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } ) } diff --git a/ui/blocks/BlocksListItem.tsx b/ui/blocks/BlocksListItem.tsx index 445312426a..de31aab684 100644 --- a/ui/blocks/BlocksListItem.tsx +++ b/ui/blocks/BlocksListItem.tsx @@ -6,7 +6,7 @@ import React from 'react'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import flameIcon from 'icons/flame.svg'; import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import { WEI } from 'lib/consts'; @@ -88,15 +88,15 @@ const BlocksListItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ) } - { !appConfig.L2.isL2Network && ( + { !config.features.rollup.isEnabled && ( - Reward { appConfig.network.currency.symbol } + Reward { config.chain.currency.symbol } { totalReward.toFixed() } ) } - { !appConfig.L2.isL2Network && ( + { !config.features.rollup.isEnabled && ( Burnt fees diff --git a/ui/blocks/BlocksTable.tsx b/ui/blocks/BlocksTable.tsx index f89df72617..083de23aa8 100644 --- a/ui/blocks/BlocksTable.tsx +++ b/ui/blocks/BlocksTable.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import BlocksTableItem from 'ui/blocks/BlocksTableItem'; import { default as Thead } from 'ui/shared/TheadSticky'; @@ -25,11 +25,11 @@ const BlocksTable = ({ data, isLoading, top, page }: Props) => { Block Size, bytes - { capitalize(getNetworkValidatorTitle()) } + { capitalize(getNetworkValidatorTitle()) } Txn - Gas used - { !appConfig.L2.isL2Network && Reward { appConfig.network.currency.symbol } } - { !appConfig.L2.isL2Network && Burnt fees { appConfig.network.currency.symbol } } + Gas used + { !config.features.rollup.isEnabled && Reward { config.chain.currency.symbol } } + { !config.features.rollup.isEnabled && Burnt fees { config.chain.currency.symbol } } diff --git a/ui/blocks/BlocksTableItem.tsx b/ui/blocks/BlocksTableItem.tsx index 20e77c48e7..6f43511ef9 100644 --- a/ui/blocks/BlocksTableItem.tsx +++ b/ui/blocks/BlocksTableItem.tsx @@ -6,7 +6,7 @@ import React from 'react'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import flameIcon from 'icons/flame.svg'; import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import { WEI } from 'lib/consts'; @@ -87,7 +87,7 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => { ) : data.tx_count } - { !appConfig.L2.isL2Network && ( + { !config.features.rollup.isEnabled && ( { BigNumber(data.gas_used || 0).toFormat() } @@ -114,7 +114,7 @@ const BlocksTableItem = ({ data, isLoading, enableTimeIncrement }: Props) => { { totalReward.toFixed(8) } - { !appConfig.L2.isL2Network && ( + { !config.features.rollup.isEnabled && ( diff --git a/ui/csvExport/CsvExportFormReCaptcha.tsx b/ui/csvExport/CsvExportFormReCaptcha.tsx index 4f3119a7ca..b99533dfbb 100644 --- a/ui/csvExport/CsvExportFormReCaptcha.tsx +++ b/ui/csvExport/CsvExportFormReCaptcha.tsx @@ -5,7 +5,7 @@ import type { UseFormReturn } from 'react-hook-form'; import type { FormFields } from './types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; interface Props { formApi: UseFormReturn; @@ -42,7 +42,7 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => { formApi.setError('reCaptcha', { type: 'required' }); }, [ formApi ]); - if (!appConfig.reCaptcha.siteKey) { + if (!config.features.csvExport.isEnabled) { return ( CSV export is not available at the moment since reCaptcha is not configured for this application. @@ -55,7 +55,7 @@ const CsvExportFormReCaptcha = ({ formApi }: Props) => { diff --git a/ui/graphQL/GraphQL.tsx b/ui/graphQL/GraphQL.tsx index 8998311f82..6f3f384775 100644 --- a/ui/graphQL/GraphQL.tsx +++ b/ui/graphQL/GraphQL.tsx @@ -3,7 +3,7 @@ import { createGraphiQLFetcher } from '@graphiql/toolkit'; import { GraphiQL } from 'graphiql'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import buildUrl from 'lib/api/buildUrl'; import 'graphiql/graphiql.css'; import isBrowser from 'lib/isBrowser'; @@ -33,7 +33,7 @@ const GraphQL = () => { const initialQuery = `{ transaction( - hash: "${ appConfig.graphQL.defaultTxnHash }" + hash: "${ config.features.graphqlApiDocs.defaultTxHash }" ) { hash blockNumber @@ -50,7 +50,7 @@ const GraphQL = () => { // or the older one subscriptions-transport-ws // so we (isstuev & vbaranov) decided to configure playground without subscriptions // in case of any complaint consider reconfigure the graphql ws server with absinthe_graphql_ws package - // subscriptionUrl: `wss://${appConfig.app.host}/socket/`, + // subscriptionUrl: `wss://${config.app.host}/socket/`, }); return ( diff --git a/ui/home/LatestBlocks.tsx b/ui/home/LatestBlocks.tsx index c423747a53..ceeec89cdb 100644 --- a/ui/home/LatestBlocks.tsx +++ b/ui/home/LatestBlocks.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { SocketMessage } from 'lib/socket/types'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery'; import useIsMobile from 'lib/hooks/useIsMobile'; import { nbsp } from 'lib/html-entities'; @@ -24,11 +24,11 @@ const BLOCK_HEIGHT_L2 = 112; const BLOCK_MARGIN = 12; const LatestBlocks = () => { - const blockHeight = appConfig.L2.isL2Network ? BLOCK_HEIGHT_L2 : BLOCK_HEIGHT_L1; + const blockHeight = config.features.rollup.isEnabled ? BLOCK_HEIGHT_L2 : BLOCK_HEIGHT_L1; const isMobile = useIsMobile(); // const blocksMaxCount = isMobile ? 2 : 3; let blocksMaxCount: number; - if (appConfig.L2.isL2Network) { + if (config.features.rollup.isEnabled) { blocksMaxCount = isMobile ? 4 : 5; } else { blocksMaxCount = isMobile ? 2 : 3; diff --git a/ui/home/LatestBlocksItem.tsx b/ui/home/LatestBlocksItem.tsx index aee5210b54..a9220ee8f9 100644 --- a/ui/home/LatestBlocksItem.tsx +++ b/ui/home/LatestBlocksItem.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { Block } from 'types/api/block'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import blockIcon from 'icons/block.svg'; import getBlockTotalReward from 'lib/block/getBlockTotalReward'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; @@ -65,7 +65,7 @@ const LatestBlocksItem = ({ block, h, isLoading }: Props) => { Txn { block.tx_count } - { !appConfig.L2.isL2Network && ( + { !config.features.rollup.isEnabled && ( <> Reward { totalReward.toFixed() } diff --git a/ui/home/LatestDepositsItem.tsx b/ui/home/LatestDepositsItem.tsx index aaa9fb1d56..a7702636f4 100644 --- a/ui/home/LatestDepositsItem.tsx +++ b/ui/home/LatestDepositsItem.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { L2DepositsItem } from 'types/api/l2Deposits'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import blockIcon from 'icons/block.svg'; import txIcon from 'icons/transactions.svg'; import dayjs from 'lib/date/dayjs'; @@ -30,7 +30,7 @@ const LatestTxsItem = ({ item, isLoading }: Props) => { const l1BlockLink = ( { const l1TxLink = ( { - { appConfig.network.currency.symbol } + { config.chain.currency.symbol } { getValueWithUnit(tx.value).dp(5).toFormat() } diff --git a/ui/home/LatestTxsItemMobile.tsx b/ui/home/LatestTxsItemMobile.tsx index 2bf121e71b..83f42d2cb1 100644 --- a/ui/home/LatestTxsItemMobile.tsx +++ b/ui/home/LatestTxsItemMobile.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { Transaction } from 'types/api/transaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import transactionIcon from 'icons/transactions.svg'; import getValueWithUnit from 'lib/getValueWithUnit'; @@ -115,11 +115,11 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => { ) } - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } { getValueWithUnit(tx.value).dp(5).toFormat() } - Fee { appConfig.network.currency.symbol } + Fee { config.chain.currency.symbol } { getValueWithUnit(tx.fee.value).dp(5).toFormat() } diff --git a/ui/home/Stats.tsx b/ui/home/Stats.tsx index 69acc93130..857012b8d9 100644 --- a/ui/home/Stats.tsx +++ b/ui/home/Stats.tsx @@ -2,7 +2,7 @@ import { Grid } from '@chakra-ui/react'; import { route } from 'nextjs-routes'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import blockIcon from 'icons/block.svg'; import clockIcon from 'icons/clock-light.svg'; import gasIcon from 'icons/gas.svg'; @@ -14,8 +14,8 @@ import { HOMEPAGE_STATS } from 'stubs/stats'; import StatsGasPrices from './StatsGasPrices'; import StatsItem from './StatsItem'; -const hasGasTracker = appConfig.homepage.showGasTracker; -const hasAvgBlockTime = appConfig.homepage.showAvgBlockTime; +const hasGasTracker = config.UI.homepage.showGasTracker; +const hasAvgBlockTime = config.UI.homepage.showAvgBlockTime; let itemsCount = 5; !hasGasTracker && itemsCount--; diff --git a/ui/home/Transactions.tsx b/ui/home/Transactions.tsx index 08bc6ec4f6..87d0fdaedc 100644 --- a/ui/home/Transactions.tsx +++ b/ui/home/Transactions.tsx @@ -1,7 +1,7 @@ import { Heading } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useHasAccount from 'lib/hooks/useHasAccount'; import LatestDeposits from 'ui/home/LatestDeposits'; import LatestTxs from 'ui/home/LatestTxs'; @@ -10,10 +10,10 @@ import TabsWithScroll from 'ui/shared/Tabs/TabsWithScroll'; const TransactionsHome = () => { const hasAccount = useHasAccount(); - if (appConfig.L2.isL2Network || hasAccount) { + if (config.features.rollup.isEnabled || hasAccount) { const tabs = [ { id: 'txn', title: 'Latest txn', component: }, - appConfig.L2.isL2Network && { id: 'deposits', title: 'Deposits (L1→L2 txn)', component: }, + config.features.rollup.isEnabled && { id: 'deposits', title: 'Deposits (L1→L2 txn)', component: }, hasAccount && { id: 'watchlist', title: 'Watch list', component: }, ].filter(Boolean); return ( diff --git a/ui/home/indicators/ChainIndicators.tsx b/ui/home/indicators/ChainIndicators.tsx index c8c7b6fbe9..8aab806da9 100644 --- a/ui/home/indicators/ChainIndicators.tsx +++ b/ui/home/indicators/ChainIndicators.tsx @@ -1,7 +1,7 @@ import { Flex, Skeleton, Text, useColorModeValue } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import Hint from 'ui/shared/Hint'; @@ -11,13 +11,13 @@ import useFetchChartData from './useFetchChartData'; import INDICATORS from './utils/indicators'; const indicators = INDICATORS - .filter(({ id }) => appConfig.homepage.charts.includes(id)) + .filter(({ id }) => config.UI.homepage.charts.includes(id)) .sort((a, b) => { - if (appConfig.homepage.charts.indexOf(a.id) > appConfig.homepage.charts.indexOf(b.id)) { + if (config.UI.homepage.charts.indexOf(a.id) > config.UI.homepage.charts.indexOf(b.id)) { return 1; } - if (appConfig.homepage.charts.indexOf(a.id) < appConfig.homepage.charts.indexOf(b.id)) { + if (config.UI.homepage.charts.indexOf(a.id) < config.UI.homepage.charts.indexOf(b.id)) { return -1; } diff --git a/ui/home/indicators/utils/indicators.tsx b/ui/home/indicators/utils/indicators.tsx index a8fc4821e4..4616aa1438 100644 --- a/ui/home/indicators/utils/indicators.tsx +++ b/ui/home/indicators/utils/indicators.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { TChainIndicator } from '../types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import globeIcon from 'icons/globe.svg'; import txIcon from 'icons/transactions.svg'; import { sortByDateDesc } from 'ui/shared/chart/utils/sorts'; @@ -28,24 +28,23 @@ const dailyTxsIndicator: TChainIndicator<'homepage_chart_txs'> = { }; const nativeTokenData = { - address: appConfig.network.currency.address || '', - name: appConfig.network.currency.name || '', + name: config.chain.currency.name || '', icon_url: '', }; const coinPriceIndicator: TChainIndicator<'homepage_chart_market'> = { id: 'coin_price', - title: `${ appConfig.network.currency.symbol } price`, + title: `${ config.chain.currency.symbol } price`, value: (stats) => '$' + Number(stats.coin_price).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 }), icon: , - hint: `${ appConfig.network.currency.symbol } token daily price in USD.`, + hint: `${ config.chain.currency.symbol } token daily price in USD.`, api: { resourceName: 'homepage_chart_market', dataFn: (response) => ([ { items: response.chart_data .map((item) => ({ date: new Date(item.date), value: Number(item.closing_price) })) .sort(sortByDateDesc), - name: `${ appConfig.network.currency.symbol } price`, + name: `${ config.chain.currency.symbol } price`, valueFormatter: (x: number) => '$' + x.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 }), } ]), }, diff --git a/ui/l2Deposits/DepositsListItem.tsx b/ui/l2Deposits/DepositsListItem.tsx index 2351fda287..aae59a0c0a 100644 --- a/ui/l2Deposits/DepositsListItem.tsx +++ b/ui/l2Deposits/DepositsListItem.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { L2DepositsItem } from 'types/api/l2Deposits'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import blockIcon from 'icons/block.svg'; import txIcon from 'icons/transactions.svg'; import dayjs from 'lib/date/dayjs'; @@ -27,7 +27,7 @@ const DepositsListItem = ({ item, isLoading }: Props) => { L1 block No { L1 txn hash { L1 txn origin { { { { maxW="100%" display="flex" overflow="hidden" - href={ appConfig.L2.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) } + href={ config.features.rollup.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: item.l1_tx_hash } }) } isLoading={ isLoading } > diff --git a/ui/l2OutputRoots/OutputRootsTableItem.tsx b/ui/l2OutputRoots/OutputRootsTableItem.tsx index 02e7be5532..d0934c9075 100644 --- a/ui/l2OutputRoots/OutputRootsTableItem.tsx +++ b/ui/l2OutputRoots/OutputRootsTableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { L2OutputRootsItem } from 'types/api/l2OutputRoots'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import txIcon from 'icons/transactions.svg'; import txBatchIcon from 'icons/txBatch.svg'; import dayjs from 'lib/date/dayjs'; @@ -47,7 +47,7 @@ const OutputRootsTableItem = ({ item, isLoading }: Props) => { diff --git a/ui/l2TxnBatches/TxnBatchesListItem.tsx b/ui/l2TxnBatches/TxnBatchesListItem.tsx index c8390b57ed..6eef28d97d 100644 --- a/ui/l2TxnBatches/TxnBatchesListItem.tsx +++ b/ui/l2TxnBatches/TxnBatchesListItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import txIcon from 'icons/transactions.svg'; import txBatchIcon from 'icons/txBatch.svg'; import dayjs from 'lib/date/dayjs'; @@ -56,7 +56,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => { @@ -72,7 +72,7 @@ const TxnBatchesListItem = ({ item, isLoading }: Props) => { diff --git a/ui/l2TxnBatches/TxnBatchesTableItem.tsx b/ui/l2TxnBatches/TxnBatchesTableItem.tsx index 1a73e48cfe..c538e76268 100644 --- a/ui/l2TxnBatches/TxnBatchesTableItem.tsx +++ b/ui/l2TxnBatches/TxnBatchesTableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { L2TxnBatchesItem } from 'types/api/l2TxnBatches'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import txIcon from 'icons/transactions.svg'; import txBatchIcon from 'icons/txBatch.svg'; import dayjs from 'lib/date/dayjs'; @@ -47,7 +47,7 @@ const TxnBatchesTableItem = ({ item, isLoading }: Props) => { { maxW="100%" display="inline-flex" key={ hash } - href={ appConfig.L2.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: hash } }) } + href={ config.features.rollup.L1BaseUrl + route({ pathname: '/tx/[hash]', query: { hash: hash } }) } isLoading={ isLoading } > diff --git a/ui/l2Withdrawals/WithdrawalsListItem.tsx b/ui/l2Withdrawals/WithdrawalsListItem.tsx index ecaa23dbc1..2994d42624 100644 --- a/ui/l2Withdrawals/WithdrawalsListItem.tsx +++ b/ui/l2Withdrawals/WithdrawalsListItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { L2WithdrawalsItem } from 'types/api/l2Withdrawals'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import txIcon from 'icons/transactions.svg'; import dayjs from 'lib/date/dayjs'; import Address from 'ui/shared/address/Address'; @@ -75,7 +75,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => { Status { item.status === 'Ready for relay' ? - { item.status } : + { item.status } : { item.status } } @@ -84,7 +84,7 @@ const WithdrawalsListItem = ({ item, isLoading }: Props) => { L1 txn hash { { item.status === 'Ready for relay' ? - { item.status } : + { item.status } : { item.status } } { item.l1_tx_hash ? ( diff --git a/ui/marketplace/useMarketplaceApps.tsx b/ui/marketplace/useMarketplaceApps.tsx index 3a0a5c34e3..61da4c4302 100644 --- a/ui/marketplace/useMarketplaceApps.tsx +++ b/ui/marketplace/useMarketplaceApps.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { MarketplaceAppOverview } from 'types/client/marketplace'; import { MarketplaceCategory } from 'types/client/marketplace'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import type { ResourceError } from 'lib/api/resources'; import useApiFetch from 'lib/hooks/useFetch'; import { MARKETPLACE_APP } from 'stubs/marketplace'; @@ -23,7 +23,7 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s const apiFetch = useApiFetch(); const { isPlaceholderData, isError, error, data } = useQuery, Array>( [ 'marketplace-apps' ], - async() => apiFetch(appConfig.marketplace.configUrl || ''), + async() => apiFetch(config.features.marketplace.configUrl || ''), { select: (data) => (data as Array).sort((a, b) => a.title.localeCompare(b.title)), placeholderData: Array(9).fill(MARKETPLACE_APP), diff --git a/ui/pages/Address.tsx b/ui/pages/Address.tsx index e8f6436369..e5243bdc74 100644 --- a/ui/pages/Address.tsx +++ b/ui/pages/Address.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { TokenType } from 'types/api/token'; import type { RoutedTab } from 'ui/shared/Tabs/types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconSuccess from 'icons/status/success.svg'; import useApiQuery from 'lib/api/useApiQuery'; import { useAppContext } from 'lib/contexts/app'; @@ -59,7 +59,7 @@ const AddressPageContent = () => { const tabs: Array = React.useMemo(() => { return [ { id: 'txs', title: 'Transactions', component: }, - appConfig.beaconChain.hasBeaconChain && addressQuery.data?.has_beacon_chain_withdrawals ? + config.features.beaconChain.isEnabled && addressQuery.data?.has_beacon_chain_withdrawals ? { id: 'withdrawals', title: 'Withdrawals', component: } : undefined, addressQuery.data?.has_token_transfers ? diff --git a/ui/pages/Block.tsx b/ui/pages/Block.tsx index d52d02fc1a..4f6ad3d17c 100644 --- a/ui/pages/Block.tsx +++ b/ui/pages/Block.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { PaginationParams } from 'ui/shared/pagination/types'; import type { RoutedTab } from 'ui/shared/Tabs/types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import { useAppContext } from 'lib/contexts/app'; import useIsMobile from 'lib/hooks/useIsMobile'; @@ -62,7 +62,7 @@ const BlockPageContent = () => { resourceName: 'block_withdrawals', pathParams: { height_or_hash: heightOrHash }, options: { - enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && appConfig.beaconChain.hasBeaconChain && tab === 'withdrawals'), + enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && config.features.beaconChain.isEnabled && tab === 'withdrawals'), placeholderData: generateListStub<'block_withdrawals'>(WITHDRAWAL, 50, { next_page_params: { index: 5, items_count: 50, @@ -81,7 +81,7 @@ const BlockPageContent = () => { const tabs: Array = React.useMemo(() => ([ { id: 'index', title: 'Details', component: }, { id: 'txs', title: 'Transactions', component: }, - appConfig.beaconChain.hasBeaconChain && Boolean(blockQuery.data?.withdrawals_count) ? + config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ? { id: 'withdrawals', title: 'Withdrawals', component: } : null, ].filter(Boolean)), [ blockQuery, blockTxsQuery, blockWithdrawalsQuery ]); diff --git a/ui/pages/Home.tsx b/ui/pages/Home.tsx index 6188309fed..0228e72509 100644 --- a/ui/pages/Home.tsx +++ b/ui/pages/Home.tsx @@ -1,7 +1,7 @@ import { Box, Heading, Flex, LightMode } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import ChainIndicators from 'ui/home/indicators/ChainIndicators'; import LatestBlocks from 'ui/home/LatestBlocks'; import Stats from 'ui/home/Stats'; @@ -16,7 +16,7 @@ const Home = () => { { size={{ base: 'md', lg: 'xl' }} lineHeight={{ base: '32px', lg: '50px' }} fontWeight={ 600 } - color={ appConfig.homepage.plate.textColor } + color={ config.UI.homepage.plate.textColor } > - Welcome to { appConfig.network.name } explorer + Welcome to { config.chain.name } explorer - { appConfig.account.isEnabled && } + { config.features.account.isEnabled && } diff --git a/ui/pages/Login.tsx b/ui/pages/Login.tsx index 47193dc888..217c1b7175 100644 --- a/ui/pages/Login.tsx +++ b/ui/pages/Login.tsx @@ -4,7 +4,7 @@ import mixpanel from 'mixpanel-browser'; import type { ChangeEvent } from 'react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import * as cookies from 'lib/cookies'; import useGradualIncrement from 'lib/hooks/useGradualIncrement'; import useToast from 'lib/hooks/useToast'; @@ -21,7 +21,7 @@ const Login = () => { React.useEffect(() => { const token = cookies.get(cookies.NAMES.API_TOKEN); - setFormVisibility(Boolean(!token && appConfig.account.isEnabled)); + setFormVisibility(Boolean(!token && config.features.account.isEnabled)); }, []); const checkSentry = React.useCallback(() => { diff --git a/ui/pages/Marketplace.tsx b/ui/pages/Marketplace.tsx index cb948ae0d3..15172d220b 100644 --- a/ui/pages/Marketplace.tsx +++ b/ui/pages/Marketplace.tsx @@ -1,7 +1,7 @@ import { Box, Icon, Link, Skeleton } from '@chakra-ui/react'; import React from 'react'; -import config from 'configs/app/config'; +import config from 'configs/app'; import PlusIcon from 'icons/plus.svg'; import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal'; import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu'; @@ -74,7 +74,7 @@ const Marketplace = () => { /> ) } - { config.marketplace.submitForm && ( + { config.features.marketplace.isEnabled && ( { fontWeight="bold" display="inline-flex" alignItems="baseline" - href={ config.marketplace.submitForm } + href={ config.features.marketplace.submitFormUrl } isExternal > { const { isLoading, isError, error, data } = useQuery, MarketplaceAppOverview>( [ 'marketplace-apps', id ], async() => { - const result = await apiFetch, unknown>(appConfig.marketplace.configUrl || ''); + const result = await apiFetch, unknown>(config.features.marketplace.configUrl); if (!Array.isArray(result)) { throw result; } @@ -58,13 +58,13 @@ const MarketplaceApp = () => { if (data && !isFrameLoading) { const message = { blockscoutColorMode: colorMode, - blockscoutRootUrl: appConfig.app.baseUrl + route({ pathname: '/' }), - blockscoutAddressExplorerUrl: appConfig.app.baseUrl + route({ pathname: '/address/[hash]', query: { hash: '' } }), - blockscoutTransactionExplorerUrl: appConfig.app.baseUrl + route({ pathname: '/tx/[hash]', query: { hash: '' } }), - blockscoutNetworkName: appConfig.network.name, - blockscoutNetworkId: Number(appConfig.network.id), - blockscoutNetworkCurrency: appConfig.network.currency, - blockscoutNetworkRpc: appConfig.network.rpcUrl, + blockscoutRootUrl: config.app.baseUrl + route({ pathname: '/' }), + blockscoutAddressExplorerUrl: config.app.baseUrl + route({ pathname: '/address/[hash]', query: { hash: '' } }), + blockscoutTransactionExplorerUrl: config.app.baseUrl + route({ pathname: '/tx/[hash]', query: { hash: '' } }), + blockscoutNetworkName: config.chain.name, + blockscoutNetworkId: Number(config.chain.id), + blockscoutNetworkCurrency: config.chain.currency, + blockscoutNetworkRpc: config.chain.rpcUrl, }; ref?.current?.contentWindow?.postMessage(message, data.url); diff --git a/ui/pages/Stats.tsx b/ui/pages/Stats.tsx index 0d95e4cd78..43ed1e106f 100644 --- a/ui/pages/Stats.tsx +++ b/ui/pages/Stats.tsx @@ -1,7 +1,7 @@ import { Box } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import Page from 'ui/shared/Page/Page'; import PageTitle from 'ui/shared/Page/PageTitle'; @@ -26,7 +26,7 @@ const Stats = () => { return ( - + diff --git a/ui/pages/Token.tsx b/ui/pages/Token.tsx index 14acc5fa68..d3219def83 100644 --- a/ui/pages/Token.tsx +++ b/ui/pages/Token.tsx @@ -8,7 +8,7 @@ import type { TokenInfo } from 'types/api/token'; import type { PaginationParams } from 'ui/shared/pagination/types'; import type { RoutedTab } from 'ui/shared/Tabs/types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconSuccess from 'icons/status/success.svg'; import iconVerifiedToken from 'icons/verified_token.svg'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery'; @@ -145,10 +145,9 @@ const TokenPageContent = () => { }, }); - const isVerifiedInfoEnabled = Boolean(appConfig.contractInfoApi.endpoint); const verifiedInfoQuery = useApiQuery('token_verified_info', { - pathParams: { hash: hashString, chainId: appConfig.network.id }, - queryOptions: { enabled: Boolean(tokenQuery.data) && isVerifiedInfoEnabled }, + pathParams: { hash: hashString, chainId: config.chain.id }, + queryOptions: { enabled: Boolean(tokenQuery.data) && config.features.verifiedTokens.isEnabled }, }); const contractTabs = useContractTabs(contractQuery.data); @@ -223,7 +222,7 @@ const TokenPageContent = () => { const titleContentAfter = ( <> { verifiedInfoQuery.data?.tokenAddress && ( - + @@ -266,7 +265,7 @@ const TokenPageContent = () => { contentAfter={ titleContentAfter } /> - + { /* should stay before tabs to scroll up with pagination */ } diff --git a/ui/pages/Transactions.tsx b/ui/pages/Transactions.tsx index 3b4ebb3423..19fc842934 100644 --- a/ui/pages/Transactions.tsx +++ b/ui/pages/Transactions.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { RoutedTab } from 'ui/shared/Tabs/types'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useHasAccount from 'lib/hooks/useHasAccount'; import useIsMobile from 'lib/hooks/useIsMobile'; import useNewTxsSocket from 'lib/hooks/useNewTxsSocket'; @@ -23,7 +23,7 @@ const TAB_LIST_PROPS = { }; const Transactions = () => { - const verifiedTitle = appConfig.network.verificationType === 'validation' ? 'Validated' : 'Mined'; + const verifiedTitle = config.chain.verificationType === 'validation' ? 'Validated' : 'Mined'; const router = useRouter(); const isMobile = useIsMobile(); const txsQuery = useQueryWithPages({ diff --git a/ui/pages/VerifiedAddresses.tsx b/ui/pages/VerifiedAddresses.tsx index 82d8f5a37c..483e9f1045 100644 --- a/ui/pages/VerifiedAddresses.tsx +++ b/ui/pages/VerifiedAddresses.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { VerifiedAddress, TokenInfoApplication, TokenInfoApplications, VerifiedAddressResponse } from 'types/api/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery'; import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken'; import getQueryParamString from 'lib/router/getQueryParamString'; @@ -37,13 +37,13 @@ const VerifiedAddresses = () => { const queryClient = useQueryClient(); const addressesQuery = useApiQuery('verified_addresses', { - pathParams: { chainId: appConfig.network.id }, + pathParams: { chainId: config.chain.id }, queryOptions: { placeholderData: { verifiedAddresses: Array(3).fill(VERIFIED_ADDRESS) }, }, }); const applicationsQuery = useApiQuery('token_info_applications', { - pathParams: { chainId: appConfig.network.id, id: undefined }, + pathParams: { chainId: config.chain.id, id: undefined }, queryOptions: { placeholderData: { submissions: Array(3).fill(TOKEN_INFO_APPLICATION) }, select: (data) => { @@ -70,7 +70,7 @@ const VerifiedAddresses = () => { const handleAddressSubmit = React.useCallback((newItem: VerifiedAddress) => { queryClient.setQueryData( - getResourceKey('verified_addresses', { pathParams: { chainId: appConfig.network.id } }), + getResourceKey('verified_addresses', { pathParams: { chainId: config.chain.id } }), (prevData: VerifiedAddressResponse | undefined) => { if (!prevData) { return { verifiedAddresses: [ newItem ] }; @@ -85,7 +85,7 @@ const VerifiedAddresses = () => { const handleApplicationSubmit = React.useCallback((newItem: TokenInfoApplication) => { setSelectedAddress(undefined); queryClient.setQueryData( - getResourceKey('token_info_applications', { pathParams: { chainId: appConfig.network.id, id: undefined } }), + getResourceKey('token_info_applications', { pathParams: { chainId: config.chain.id, id: undefined } }), (prevData: TokenInfoApplications | undefined) => { if (!prevData) { return { submissions: [ newItem ] }; @@ -174,7 +174,7 @@ const VerifiedAddresses = () => { Before starting, make sure that: - The source code for the smart contract is deployed on “{ appConfig.network.name }”. + The source code for the smart contract is deployed on “{ config.chain.name }”. The source code is verified (if not yet verified, you can use this tool diff --git a/ui/pages/Withdrawals.tsx b/ui/pages/Withdrawals.tsx index 3dc0a6be0f..ef5c21293f 100644 --- a/ui/pages/Withdrawals.tsx +++ b/ui/pages/Withdrawals.tsx @@ -2,7 +2,7 @@ import { Flex, Hide, Show, Skeleton, Text } from '@chakra-ui/react'; import BigNumber from 'bignumber.js'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useApiQuery from 'lib/api/useApiQuery'; import getCurrencyValue from 'lib/getCurrencyValue'; import useIsMobile from 'lib/hooks/useIsMobile'; @@ -68,7 +68,8 @@ const Withdrawals = () => { const { valueStr } = getCurrencyValue({ value: countersQuery.data.withdrawal_sum }); return ( - { BigNumber(countersQuery.data.withdrawal_count).toFormat() } withdrawals processed and { valueStr } { appConfig.beaconChain.currencySymbol } withdrawn + { BigNumber(countersQuery.data.withdrawal_count).toFormat() } withdrawals processed + and { valueStr } { config.features.beaconChain.currency.symbol } withdrawn ); })(); diff --git a/ui/shared/AddressActions/Menu.tsx b/ui/shared/AddressActions/Menu.tsx index d4e767c5b8..3303dbd3a9 100644 --- a/ui/shared/AddressActions/Menu.tsx +++ b/ui/shared/AddressActions/Menu.tsx @@ -2,7 +2,7 @@ import { Button, Menu, MenuButton, MenuList, Icon, Flex, Skeleton } from '@chakr import { useRouter } from 'next/router'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconArrow from 'icons/arrows/east-mini.svg'; import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed'; import getQueryParamString from 'lib/router/getQueryParamString'; @@ -37,7 +37,7 @@ const AddressActions = ({ isLoading }: Props) => { - { isTokenPage && appConfig.contractInfoApi.endpoint && appConfig.adminServiceApi.endpoint && appConfig.account.isEnabled && + { isTokenPage && config.features.addressVerification.isEnabled && } diff --git a/ui/shared/AddressActions/TokenInfoMenuItem.tsx b/ui/shared/AddressActions/TokenInfoMenuItem.tsx index 9ae9279e23..c814fd8a9e 100644 --- a/ui/shared/AddressActions/TokenInfoMenuItem.tsx +++ b/ui/shared/AddressActions/TokenInfoMenuItem.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/router'; import type { Route } from 'nextjs-routes'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconEdit from 'icons/edit.svg'; import useApiQuery from 'lib/api/useApiQuery'; import useHasAccount from 'lib/hooks/useHasAccount'; @@ -21,19 +21,19 @@ const TokenInfoMenuItem = ({ className, hash, onBeforeClick }: Props) => { const isAuth = useHasAccount(); const verifiedAddressesQuery = useApiQuery('verified_addresses', { - pathParams: { chainId: appConfig.network.id }, + pathParams: { chainId: config.chain.id }, queryOptions: { enabled: isAuth, }, }); const applicationsQuery = useApiQuery('token_info_applications', { - pathParams: { chainId: appConfig.network.id, id: undefined }, + pathParams: { chainId: config.chain.id, id: undefined }, queryOptions: { enabled: isAuth, }, }); const tokenInfoQuery = useApiQuery('token_verified_info', { - pathParams: { hash, chainId: appConfig.network.id }, + pathParams: { hash, chainId: config.chain.id }, queryOptions: { refetchOnMount: false, }, diff --git a/ui/shared/AddressHeadingInfo.tsx b/ui/shared/AddressHeadingInfo.tsx index a5bd554da3..75cdef8828 100644 --- a/ui/shared/AddressHeadingInfo.tsx +++ b/ui/shared/AddressHeadingInfo.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { Address } from 'types/api/address'; import type { TokenInfo } from 'types/api/token'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton'; import AddressQrCode from 'ui/address/details/AddressQrCode'; import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet'; @@ -36,11 +36,11 @@ const AddressHeadingInfo = ({ address, token, isLinkDisabled, isLoading }: Props /> { !isLoading && address.is_contract && token && } - { !isLoading && !address.is_contract && appConfig.account.isEnabled && ( + { !isLoading && !address.is_contract && config.features.account.isEnabled && ( ) } - { appConfig.account.isEnabled && } + { config.features.account.isEnabled && } ); }; diff --git a/ui/shared/AppError/AppErrorTooManyRequests.tsx b/ui/shared/AppError/AppErrorTooManyRequests.tsx index bc51becaf7..22cec54076 100644 --- a/ui/shared/AppError/AppErrorTooManyRequests.tsx +++ b/ui/shared/AppError/AppErrorTooManyRequests.tsx @@ -2,7 +2,7 @@ import { Box, Heading, Icon, Text, chakra } from '@chakra-ui/react'; import React from 'react'; import ReCaptcha from 'react-google-recaptcha'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import icon429 from 'icons/error-pages/429.svg'; import buildUrl from 'lib/api/buildUrl'; import useFetch from 'lib/hooks/useFetch'; @@ -60,10 +60,10 @@ const AppErrorTooManyRequests = ({ className }: Props) => { You have exceeded the request rate for a given time period. Please reduce the number of requests and try again soon. - { appConfig.reCaptcha.siteKey && ( + { config.services.reCaptcha.siteKey && ( ) } diff --git a/ui/shared/GoogleAnalytics.tsx b/ui/shared/GoogleAnalytics.tsx index 10ce376622..2ff5147b3f 100644 --- a/ui/shared/GoogleAnalytics.tsx +++ b/ui/shared/GoogleAnalytics.tsx @@ -1,14 +1,14 @@ import Script from 'next/script'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; const GoogleAnalytics = () => { - if (!appConfig.googleAnalytics.propertyId) { + if (!config.features.googleAnalytics.isEnabled) { return null; } - const id = appConfig.googleAnalytics.propertyId; + const id = config.features.googleAnalytics.propertyId; return ( <> diff --git a/ui/shared/NetworkAddToWallet.tsx b/ui/shared/NetworkAddToWallet.tsx index fb804a2d98..3d0d18ea29 100644 --- a/ui/shared/NetworkAddToWallet.tsx +++ b/ui/shared/NetworkAddToWallet.tsx @@ -1,7 +1,7 @@ import { Button, Icon, chakra } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useToast from 'lib/hooks/useToast'; import useProvider from 'lib/web3/useProvider'; import { WALLETS_INFO } from 'lib/web3/wallets'; @@ -16,24 +16,24 @@ const NetworkAddToWallet = ({ className }: Props) => { const handleClick = React.useCallback(async() => { try { - const hexadecimalChainId = '0x' + Number(appConfig.network.id).toString(16); - const config = { + const hexadecimalChainId = '0x' + Number(config.chain.id).toString(16); + const params = { method: 'wallet_addEthereumChain', params: [ { chainId: hexadecimalChainId, - chainName: appConfig.network.name, + chainName: config.chain.name, nativeCurrency: { - name: appConfig.network.currency.name, - symbol: appConfig.network.currency.symbol, - decimals: appConfig.network.currency.decimals, + name: config.chain.currency.name, + symbol: config.chain.currency.symbol, + decimals: config.chain.currency.decimals, }, - rpcUrls: [ appConfig.network.rpcUrl ], - blockExplorerUrls: [ appConfig.app.baseUrl ], + rpcUrls: [ config.chain.rpcUrl ], + blockExplorerUrls: [ config.app.baseUrl ], } ], // in wagmi types for wallet_addEthereumChain method is not provided // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; - await provider?.request?.(config); + await provider?.request?.(params); toast({ position: 'top-right', title: 'Success', @@ -54,16 +54,20 @@ const NetworkAddToWallet = ({ className }: Props) => { } }, [ provider, toast ]); - if (!provider || !appConfig.network.rpcUrl) { + if (!provider || !config.chain.rpcUrl) { return null; } - const defaultWallet = appConfig.web3.defaultWallet; + const defaultWallet = config.features.web3Wallet.defaultWallet; + + if (defaultWallet === 'none') { + return null; + } return ( ); }; diff --git a/ui/shared/NetworkExplorers.tsx b/ui/shared/NetworkExplorers.tsx index a2d14a91a0..ea4a8a5b25 100644 --- a/ui/shared/NetworkExplorers.tsx +++ b/ui/shared/NetworkExplorers.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { NetworkExplorer as TNetworkExplorer } from 'types/networks'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import arrowIcon from 'icons/arrows/east-mini.svg'; import explorerIcon from 'icons/explorer.svg'; import LinkExternal from 'ui/shared/LinkExternal'; @@ -18,7 +18,7 @@ interface Props { const NetworkExplorers = ({ className, type, pathParam, hideText }: Props) => { const { isOpen, onToggle, onClose } = useDisclosure(); - const explorersLinks = appConfig.network.explorers + const explorersLinks = config.UI.explorers.items .filter((explorer) => explorer.paths[type]) .map((explorer) => { const url = new URL(explorer.paths[type] + '/' + pathParam, explorer.baseUrl); diff --git a/ui/shared/Page/PageContent.tsx b/ui/shared/Page/PageContent.tsx index e47c73c665..f9cd41aa96 100644 --- a/ui/shared/Page/PageContent.tsx +++ b/ui/shared/Page/PageContent.tsx @@ -1,7 +1,7 @@ import { Box } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import IndexingAlertBlocks from 'ui/home/IndexingAlertBlocks'; interface Props { @@ -18,7 +18,7 @@ const PageContent = ({ children, isHomePage }: Props) => { paddingBottom={ 10 } paddingTop={{ base: isHomePage ? '88px' : '138px', lg: 0 }} > - { !appConfig.hideIndexingAlert && } + { !config.UI.indexingAlert.isHidden && } { children } ); diff --git a/ui/shared/TokenLogo.tsx b/ui/shared/TokenLogo.tsx index fe7ee282c1..d489e3caaf 100644 --- a/ui/shared/TokenLogo.tsx +++ b/ui/shared/TokenLogo.tsx @@ -6,7 +6,7 @@ import type { TokenInfo } from 'types/api/token'; import TokenLogoPlaceholder from 'ui/shared/TokenLogoPlaceholder'; export interface Props { - data?: Pick; + data?: Pick; className?: string; isLoading?: boolean; } diff --git a/ui/shared/Web3ModalProvider.tsx b/ui/shared/Web3ModalProvider.tsx index f594ddf07b..25fb25cc30 100644 --- a/ui/shared/Web3ModalProvider.tsx +++ b/ui/shared/Web3ModalProvider.tsx @@ -6,35 +6,35 @@ import React from 'react'; import type { Chain } from 'wagmi'; import { configureChains, createConfig, WagmiConfig } from 'wagmi'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; const getConfig = () => { try { - if (!appConfig.walletConnect.projectId) { + if (!config.features.blockchainInteraction.walletConnect.projectId) { throw new Error('WalletConnect Project ID is not set'); } const currentChain: Chain = { - id: Number(appConfig.network.id), - name: appConfig.network.name || '', - network: appConfig.network.name || '', + id: Number(config.chain.id), + name: config.chain.name || '', + network: config.chain.name || '', nativeCurrency: { - decimals: appConfig.network.currency.decimals, - name: appConfig.network.currency.name || '', - symbol: appConfig.network.currency.symbol || '', + decimals: config.chain.currency.decimals, + name: config.chain.currency.name || '', + symbol: config.chain.currency.symbol || '', }, rpcUrls: { 'public': { - http: [ appConfig.network.rpcUrl || '' ], + http: [ config.chain.rpcUrl || '' ], }, 'default': { - http: [ appConfig.network.rpcUrl || '' ], + http: [ config.chain.rpcUrl || '' ], }, }, blockExplorers: { 'default': { name: 'Blockscout', - url: appConfig.app.baseUrl, + url: config.app.baseUrl, }, }, }; @@ -44,13 +44,13 @@ const getConfig = () => { const { publicClient } = configureChains(chains, [ jsonRpcProvider({ rpc: () => ({ - http: appConfig.network.rpcUrl || '', + http: config.chain.rpcUrl || '', }), }), ]); const wagmiConfig = createConfig({ autoConnect: true, - connectors: w3mConnectors({ projectId: appConfig.walletConnect.projectId, chains }), + connectors: w3mConnectors({ projectId: config.features.blockchainInteraction.walletConnect.projectId, chains }), publicClient, }); const ethereumClient = new EthereumClient(wagmiConfig, chains); @@ -72,7 +72,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => { const modalZIndex = useToken('zIndices', 'modal'); const web3ModalTheme = useColorModeValue('light', 'dark'); - if (!wagmiConfig || !ethereumClient || !appConfig.walletConnect.projectId) { + if (!wagmiConfig || !ethereumClient || !config.features.blockchainInteraction.isEnabled) { return typeof fallback === 'function' ? fallback() : (fallback || null); } @@ -82,7 +82,7 @@ const Web3ModalProvider = ({ children, fallback }: Props) => { { children } { const hasAdblockCookie = cookies.get(cookies.NAMES.ADBLOCK_DETECTED, useAppContext().cookies); - if (appConfig.ad.adBannerProvider === 'none' || hasAdblockCookie) { + if (!config.features.adsBanner.isEnabled || hasAdblockCookie) { return null; } const content = (() => { - switch (appConfig.ad.adBannerProvider) { + switch (config.features.adsBanner.provider) { case 'adbutler': return ; case 'coinzilla': @@ -32,7 +32,7 @@ const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: bo className={ className } isLoaded={ !isLoading } borderRadius="none" - maxW={ appConfig.ad.adBannerProvider === 'adbutler' ? appConfig.ad.adButlerConfigDesktop?.width : '728px' } + maxW={ config.features.adsBanner.provider === 'adbutler' ? config.features.adsBanner.adButler.config.desktop?.width : '728px' } w="100%" > { content } diff --git a/ui/shared/ad/AdbutlerBanner.tsx b/ui/shared/ad/AdbutlerBanner.tsx index 3e4639829c..7feb8375b5 100644 --- a/ui/shared/ad/AdbutlerBanner.tsx +++ b/ui/shared/ad/AdbutlerBanner.tsx @@ -3,7 +3,7 @@ import { useRouter } from 'next/navigation'; import Script from 'next/script'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useIsMobile from 'lib/hooks/useIsMobile'; import isBrowser from 'lib/isBrowser'; import { connectAdbutler, placeAd, ADBUTLER_ACCOUNT } from 'ui/shared/ad/adbutlerScript'; @@ -19,16 +19,22 @@ const AdbutlerBanner = ({ className }: { className?: string }) => { } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: - let plc = window[`plc${ appConfig.ad.adButlerConfigMobile?.id }`] || 0; - const config = isMobile ? appConfig.ad.adButlerConfigMobile : appConfig.ad.adButlerConfigDesktop; + let plc = window[`plc${ config.features.adsBanner.adButler.config.mobile?.id }`] || 0; + const adButlerConfig = isMobile ? config.features.adsBanner.adButler.config.mobile : config.features.adsBanner.adButler.config.desktop; const banner = document.getElementById('ad-banner'); if (banner) { - banner.innerHTML = '<' + 'div id="placement_' + config?.id + '_' + plc + '">'; + banner.innerHTML = '<' + 'div id="placement_' + adButlerConfig?.id + '_' + plc + '">'; } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: window.AdButler.ads.push({ handler: function(opt) { - window.AdButler.register(ADBUTLER_ACCOUNT, config?.id, [ config?.width, config?.height ], `placement_${ config?.id }_` + opt.place, opt); + window.AdButler.register( + ADBUTLER_ACCOUNT, + adButlerConfig?.id, + [ adButlerConfig?.width, adButlerConfig?.height ], + `placement_${ adButlerConfig?.id }_` + opt.place, + opt, + ); }, opt: { place: plc++, keywords: abkw, domain: 'servedbyadbutler.com', click: 'CLICK_MACRO_PLACEHOLDER' } }); } }, [ router, isMobile ]); diff --git a/ui/shared/ad/SliseBanner.tsx b/ui/shared/ad/SliseBanner.tsx index 056f9f81ff..56ae2a7f3a 100644 --- a/ui/shared/ad/SliseBanner.tsx +++ b/ui/shared/ad/SliseBanner.tsx @@ -2,7 +2,7 @@ import { Flex, chakra } from '@chakra-ui/react'; import { SliseAd } from '@slise/embed-react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; const SliseBanner = ({ className }: { className?: string }) => { @@ -10,14 +10,14 @@ const SliseBanner = ({ className }: { className?: string }) => { <> diff --git a/ui/shared/ad/TextAd.tsx b/ui/shared/ad/TextAd.tsx index 32bfd008de..58fca43814 100644 --- a/ui/shared/ad/TextAd.tsx +++ b/ui/shared/ad/TextAd.tsx @@ -1,7 +1,7 @@ import { chakra } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { useAppContext } from 'lib/contexts/app'; import * as cookies from 'lib/cookies'; @@ -10,7 +10,7 @@ import CoinzillaTextAd from './CoinzillaTextAd'; const TextAd = ({ className }: {className?: string}) => { const hasAdblockCookie = cookies.get(cookies.NAMES.ADBLOCK_DETECTED, useAppContext().cookies); - if (appConfig.ad.adTextProvider === 'none' || hasAdblockCookie) { + if (!config.features.adsText.isEnabled || hasAdblockCookie) { return null; } diff --git a/ui/shared/ad/adbutlerScript.ts b/ui/shared/ad/adbutlerScript.ts index ba0401613a..28cceaa883 100644 --- a/ui/shared/ad/adbutlerScript.ts +++ b/ui/shared/ad/adbutlerScript.ts @@ -1,5 +1,5 @@ /* eslint-disable max-len */ -import appConfig from 'configs/app/config'; +import config from 'configs/app'; export const ADBUTLER_ACCOUNT = 182226; @@ -10,12 +10,12 @@ var AdButler = AdButler || {}; AdButler.ads = AdButler.ads || []; var abkw = window.abkw || ''; const isMobile = window.matchMedia("only screen and (max-width: 1000px)").matches; if (isMobile) { - var plc${ appConfig.ad.adButlerConfigMobile?.id } = window.plc${ appConfig.ad.adButlerConfigMobile?.id } || 0; - document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_${ appConfig.ad.adButlerConfigMobile?.id }_'+plc${ appConfig.ad.adButlerConfigMobile?.id }+'">'; - AdButler.ads.push({handler: function(opt){ AdButler.register(${ ADBUTLER_ACCOUNT }, ${ appConfig.ad.adButlerConfigMobile?.id }, [${ appConfig.ad.adButlerConfigMobile?.width },${ appConfig.ad.adButlerConfigMobile?.height }], 'placement_${ appConfig.ad.adButlerConfigMobile?.id }_'+opt.place, opt); }, opt: { place: plc${ appConfig.ad.adButlerConfigMobile?.id }++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }}); + var plc${ config.features.adsBanner.adButler.config.mobile?.id } = window.plc${ config.features.adsBanner.adButler.config.mobile?.id } || 0; + document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_${ config.features.adsBanner.adButler.config.mobile?.id }_'+plc${ config.features.adsBanner.adButler.config.mobile?.id }+'">'; + AdButler.ads.push({handler: function(opt){ AdButler.register(${ ADBUTLER_ACCOUNT }, ${ config.features.adsBanner.adButler.config.mobile?.id }, [${ config.features.adsBanner.adButler.config.mobile?.width },${ config.features.adsBanner.adButler.config.mobile?.height }], 'placement_${ config.features.adsBanner.adButler.config.mobile?.id }_'+opt.place, opt); }, opt: { place: plc${ config.features.adsBanner.adButler.config.mobile?.id }++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }}); } else { - var plc${ appConfig.ad.adButlerConfigDesktop?.id } = window.plc${ appConfig.ad.adButlerConfigDesktop?.id } || 0; - document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_${ appConfig.ad.adButlerConfigDesktop?.id }_'+plc${ appConfig.ad.adButlerConfigDesktop?.id }+'">'; - AdButler.ads.push({handler: function(opt){ AdButler.register(${ ADBUTLER_ACCOUNT }, ${ appConfig.ad.adButlerConfigDesktop?.id }, [${ appConfig.ad.adButlerConfigDesktop?.width },${ appConfig.ad.adButlerConfigDesktop?.height }], 'placement_${ appConfig.ad.adButlerConfigDesktop?.id }_'+opt.place, opt); }, opt: { place: plc${ appConfig.ad.adButlerConfigDesktop?.id }++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }}); + var plc${ config.features.adsBanner.adButler.config.desktop?.id } = window.plc${ config.features.adsBanner.adButler.config.desktop?.id } || 0; + document.getElementById('ad-banner').innerHTML = '<'+'div id="placement_${ config.features.adsBanner.adButler.config.desktop?.id }_'+plc${ config.features.adsBanner.adButler.config.desktop?.id }+'">'; + AdButler.ads.push({handler: function(opt){ AdButler.register(${ ADBUTLER_ACCOUNT }, ${ config.features.adsBanner.adButler.config.desktop?.id }, [${ config.features.adsBanner.adButler.config.desktop?.width },${ config.features.adsBanner.adButler.config.desktop?.height }], 'placement_${ config.features.adsBanner.adButler.config.desktop?.id }_'+opt.place, opt); }, opt: { place: plc${ config.features.adsBanner.adButler.config.desktop?.id }++, keywords: abkw, domain: 'servedbyadbutler.com', click:'CLICK_MACRO_PLACEHOLDER' }}); } `; diff --git a/ui/shared/address/AddressAddToWallet.tsx b/ui/shared/address/AddressAddToWallet.tsx index 1503b698c0..8ef3b04bc9 100644 --- a/ui/shared/address/AddressAddToWallet.tsx +++ b/ui/shared/address/AddressAddToWallet.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { TokenInfo } from 'types/api/token'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useToast from 'lib/hooks/useToast'; import useProvider from 'lib/web3/useProvider'; import { WALLETS_INFO } from 'lib/web3/wallets'; @@ -64,7 +64,11 @@ const AddressAddToWallet = ({ className, token, isLoading }: Props) => { return ; } - const defaultWallet = appConfig.web3.defaultWallet; + const defaultWallet = config.features.web3Wallet.defaultWallet; + + if (defaultWallet === 'none') { + return null; + } return ( diff --git a/ui/snippets/footer/Footer.tsx b/ui/snippets/footer/Footer.tsx index 97538aee36..8be4793f17 100644 --- a/ui/snippets/footer/Footer.tsx +++ b/ui/snippets/footer/Footer.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { CustomLinksGroup } from 'types/footerLinks'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import discussionsIcon from 'icons/discussions.svg'; import editIcon from 'icons/edit.svg'; import discordIcon from 'icons/social/discord.svg'; @@ -23,7 +23,7 @@ import getApiVersionUrl from './utils/getApiVersionUrl'; const MAX_LINKS_COLUMNS = 3; -// const FRONT_VERSION_URL = `https://github.com/blockscout/frontend/tree/${ appConfig.footer.frontendVersion }`; +// const FRONT_VERSION_URL = `https://github.com/blockscout/frontend/tree/${ config.UI.footer.frontendVersion }`; const Footer = () => { @@ -71,9 +71,9 @@ const Footer = () => { const { isLoading, data: linksData } = useQuery, Array>( [ 'footer-links' ], - async() => fetch(appConfig.footer.links || ''), + async() => fetch(config.UI.footer.links || ''), { - enabled: Boolean(appConfig.footer.links), + enabled: Boolean(config.UI.footer.links), staleTime: Infinity, }); @@ -82,7 +82,7 @@ const Footer = () => { - { !appConfig.hideIndexingAlert && } + { !config.UI.indexingAlert.isHidden && } @@ -97,34 +97,34 @@ const Footer = () => { Backend: { backendVersionData?.backend_version } ) } - { (appConfig.footer.frontendVersion || appConfig.footer.frontendCommit) && ( + { (config.UI.footer.frontendVersion || config.UI.footer.frontendCommit) && ( - { /* Frontend: { appConfig.footer.frontendVersion } */ } - Frontend: { [ appConfig.footer.frontendVersion, appConfig.footer.frontendCommit ].filter(Boolean).join('+') } + { /* Frontend: { config.UI.footer.frontendVersion } */ } + Frontend: { [ config.UI.footer.frontendVersion, config.UI.footer.frontendCommit ].filter(Boolean).join('+') } ) } - - { appConfig.footer.links && Blockscout } + + { config.UI.footer.links && Blockscout } { BLOCKSCOUT_LINKS.map(link => ) } - { appConfig.footer.links && isLoading && ( + { config.UI.footer.links && isLoading && ( Array.from(Array(3)).map((i, index) => ( @@ -134,7 +134,7 @@ const Footer = () => { )) ) } - { appConfig.footer.links && linksData && ( + { config.UI.footer.links && linksData && ( linksData.slice(0, MAX_LINKS_COLUMNS).map(linkGroup => ( { linkGroup.title } diff --git a/ui/snippets/header/Burger.tsx b/ui/snippets/header/Burger.tsx index 814be21f5f..dd9d7d5da5 100644 --- a/ui/snippets/header/Burger.tsx +++ b/ui/snippets/header/Burger.tsx @@ -1,7 +1,7 @@ import { Icon, Box, Flex, Drawer, DrawerOverlay, DrawerContent, DrawerBody, useColorModeValue, useDisclosure } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import burgerIcon from 'icons/burger.svg'; import testnetIcon from 'icons/testnet.svg'; import NavigationMobile from 'ui/snippets/navigation/NavigationMobile'; @@ -44,10 +44,10 @@ const Burger = () => { - { appConfig.network.isTestnet && } + { config.chain.isTestnet && } - { appConfig.navigation.featuredNetworks ? ( + { config.UI.sidebar.featuredNetworks ? ( { > - { appConfig.account.isEnabled ? : } + { config.features.account.isEnabled ? : } { !isHomePage && searchBar } @@ -52,7 +52,7 @@ const Header = ({ isHomePage, renderSearchBar }: Props) => { paddingTop={ 9 } display={{ base: 'none', lg: 'block' }} > - { !appConfig.hideIndexingAlert && } + { !config.UI.indexingAlert.isHidden && } { !isHomePage && ( { { searchBar } - { appConfig.account.isEnabled && } + { config.features.account.isEnabled && } ) } diff --git a/ui/snippets/navigation/NavigationDesktop.tsx b/ui/snippets/navigation/NavigationDesktop.tsx index 696911e9a1..ad6ae7da1b 100644 --- a/ui/snippets/navigation/NavigationDesktop.tsx +++ b/ui/snippets/navigation/NavigationDesktop.tsx @@ -1,7 +1,7 @@ import { Flex, Box, VStack, Icon, useColorModeValue } from '@chakra-ui/react'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import chevronIcon from 'icons/arrows/east-mini.svg'; import testnetIcon from 'icons/testnet.svg'; import { useAppContext } from 'lib/contexts/app'; @@ -60,7 +60,7 @@ const NavigationDesktop = () => { width={{ lg: isExpanded ? '229px' : '92px', xl: isCollapsed ? '92px' : '229px' }} { ...getDefaultTransitionProps({ transitionProperty: 'width, padding' }) } > - { appConfig.network.isTestnet && } + { config.chain.isTestnet && } { transitionTimingFunction="ease" > - { Boolean(appConfig.navigation.featuredNetworks) && } + { Boolean(config.UI.sidebar.featuredNetworks) && } diff --git a/ui/snippets/networkMenu/NetworkLogo.tsx b/ui/snippets/networkMenu/NetworkLogo.tsx index 1baff7ab3e..0a76808486 100644 --- a/ui/snippets/networkMenu/NetworkLogo.tsx +++ b/ui/snippets/networkMenu/NetworkLogo.tsx @@ -2,7 +2,7 @@ import { Icon, Box, Image, useColorModeValue, Skeleton } from '@chakra-ui/react' import { route } from 'nextjs-routes'; import React from 'react'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconPlaceholder from 'icons/networks/icon-placeholder.svg'; import logoPlaceholder from 'icons/networks/logo-placeholder.svg'; @@ -25,7 +25,7 @@ const LogoFallback = ({ isCollapsed, isSmall }: { isCollapsed?: boolean; isSmall xl: isCollapsed ? 'none' : 'block', }; - if (appConfig.network[field].default) { + if (config.UI.sidebar[field].default) { return ; } @@ -42,11 +42,11 @@ const LogoFallback = ({ isCollapsed, isSmall }: { isCollapsed?: boolean; isSmall const NetworkLogo = ({ isCollapsed, onClick }: Props) => { - const logoSrc = useColorModeValue(appConfig.network.logo.default, appConfig.network.logo.dark || appConfig.network.logo.default); - const iconSrc = useColorModeValue(appConfig.network.icon.default, appConfig.network.icon.dark || appConfig.network.icon.default); + const logoSrc = useColorModeValue(config.UI.sidebar.logo.default, config.UI.sidebar.logo.dark || config.UI.sidebar.logo.default); + const iconSrc = useColorModeValue(config.UI.sidebar.icon.default, config.UI.sidebar.icon.dark || config.UI.sidebar.icon.default); const darkModeFilter = { filter: 'brightness(0) invert(1)' }; - const logoStyle = useColorModeValue({}, !appConfig.network.logo.dark ? darkModeFilter : {}); - const iconStyle = useColorModeValue({}, !appConfig.network.icon.dark ? darkModeFilter : {}); + const logoStyle = useColorModeValue({}, !config.UI.sidebar.logo.dark ? darkModeFilter : {}); + const iconStyle = useColorModeValue({}, !config.UI.sidebar.icon.dark ? darkModeFilter : {}); return ( // TODO switch to when main page for network will be ready @@ -66,7 +66,7 @@ const NetworkLogo = ({ isCollapsed, onClick }: Props) => { w="auto" h="100%" src={ logoSrc } - alt={ `${ appConfig.network.name } network logo` } + alt={ `${ config.chain.name } network logo` } fallback={ } display={{ base: 'block', lg: isCollapsed === false ? 'block' : 'none', xl: isCollapsed ? 'none' : 'block' }} style={ logoStyle } @@ -76,7 +76,7 @@ const NetworkLogo = ({ isCollapsed, onClick }: Props) => { w="auto" h="100%" src={ iconSrc } - alt={ `${ appConfig.network.name } network logo` } + alt={ `${ config.chain.name } network logo` } fallback={ } display={{ base: 'none', lg: isCollapsed === false ? 'none' : 'block', xl: isCollapsed ? 'block' : 'none' }} style={ iconStyle } diff --git a/ui/snippets/networkMenu/useNetworkMenu.tsx b/ui/snippets/networkMenu/useNetworkMenu.tsx index 6e8874c9ac..08842b94fd 100644 --- a/ui/snippets/networkMenu/useNetworkMenu.tsx +++ b/ui/snippets/networkMenu/useNetworkMenu.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { FeaturedNetwork, NetworkGroup } from 'types/networks'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import type { ResourceError } from 'lib/api/resources'; import useApiFetch from 'lib/hooks/useFetch'; @@ -16,9 +16,9 @@ export default function useNetworkMenu() { const apiFetch = useApiFetch(); const { isLoading, data } = useQuery, Array>( [ 'featured-network' ], - async() => apiFetch(appConfig.navigation.featuredNetworks || ''), + async() => apiFetch(config.UI.sidebar.featuredNetworks || ''), { - enabled: Boolean(appConfig.navigation.featuredNetworks) && isOpen, + enabled: Boolean(config.UI.sidebar.featuredNetworks) && isOpen, staleTime: Infinity, }); diff --git a/ui/snippets/profileMenu/ProfileMenuContent.tsx b/ui/snippets/profileMenu/ProfileMenuContent.tsx index 5e559e6fea..0570a11057 100644 --- a/ui/snippets/profileMenu/ProfileMenuContent.tsx +++ b/ui/snippets/profileMenu/ProfileMenuContent.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { UserInfo } from 'types/api/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import useNavItems from 'lib/hooks/useNavItems'; import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps'; import NavLink from 'ui/snippets/navigation/NavLink'; @@ -46,7 +46,7 @@ const ProfileMenuContent = ({ data }: Props) => { - + ); diff --git a/ui/token/TokenVerifiedInfo.tsx b/ui/token/TokenVerifiedInfo.tsx index 0c2723928a..8c397e9241 100644 --- a/ui/token/TokenVerifiedInfo.tsx +++ b/ui/token/TokenVerifiedInfo.tsx @@ -4,22 +4,22 @@ import React from 'react'; import type { TokenVerifiedInfo as TTokenVerifiedInfo } from 'types/api/token'; +import config from 'configs/app'; import LinkExternal from 'ui/shared/LinkExternal'; import TokenProjectInfo from './TokenProjectInfo'; interface Props { verifiedInfoQuery: UseQueryResult; - isVerifiedInfoEnabled: boolean; } -const TokenVerifiedInfo = ({ verifiedInfoQuery, isVerifiedInfoEnabled }: Props) => { +const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => { const { data, isLoading, isError } = verifiedInfoQuery; const websiteLinkBg = useColorModeValue('gray.100', 'gray.700'); const content = (() => { - if (!isVerifiedInfoEnabled) { + if (!config.features.verifiedTokens.isEnabled) { return null; } diff --git a/ui/tokenInfo/TokenInfoForm.tsx b/ui/tokenInfo/TokenInfoForm.tsx index b46b7fb43d..9d7f33615a 100644 --- a/ui/tokenInfo/TokenInfoForm.tsx +++ b/ui/tokenInfo/TokenInfoForm.tsx @@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'; import type { Fields } from './types'; import type { TokenInfoApplication } from 'types/api/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import type { ResourceError } from 'lib/api/resources'; import useApiFetch from 'lib/api/useApiFetch'; import useApiQuery from 'lib/api/useApiQuery'; @@ -49,7 +49,7 @@ const TokenInfoForm = ({ address, tokenName, application, onSubmit }: Props) => const toast = useToast(); const configQuery = useApiQuery('token_info_applications_config', { - pathParams: { chainId: appConfig.network.id }, + pathParams: { chainId: config.chain.id }, }); const formApi = useForm({ @@ -64,7 +64,7 @@ const TokenInfoForm = ({ address, tokenName, application, onSubmit }: Props) => const isNewApplication = !application?.id || [ 'REJECTED', 'APPROVED' ].includes(application.status); const result = await apiFetch<'token_info_applications', TokenInfoApplication, { message: string }>('token_info_applications', { - pathParams: { chainId: appConfig.network.id, id: !isNewApplication ? application.id : undefined }, + pathParams: { chainId: config.chain.id, id: !isNewApplication ? application.id : undefined }, fetchParams: { method: isNewApplication ? 'POST' : 'PUT', body: { submission }, diff --git a/ui/tx/TxDetails.tsx b/ui/tx/TxDetails.tsx index 782ff71a9b..9fdb3b0f52 100644 --- a/ui/tx/TxDetails.tsx +++ b/ui/tx/TxDetails.tsx @@ -18,7 +18,7 @@ import { route } from 'nextjs-routes'; import React from 'react'; import { scroller, Element } from 'react-scroll'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import clockIcon from 'icons/clock.svg'; import flameIcon from 'icons/flame.svg'; import errorIcon from 'icons/status/error.svg'; @@ -124,7 +124,7 @@ const TxDetails = () => { return ( <> - { appConfig.network.isTestnet && This is a { appConfig.network.name } testnet transaction only } + { config.chain.isTestnet && This is a { config.chain.name } testnet transaction only } { socketStatus && ( @@ -281,7 +281,7 @@ const TxDetails = () => { > @@ -293,7 +293,7 @@ const TxDetails = () => { > { isLoading={ isPlaceholderData } > - { BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { BigNumber(data.gas_price).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } ({ BigNumber(data.gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) @@ -354,22 +354,22 @@ const TxDetails = () => { ) } ) } - { data.tx_burnt_fee && !appConfig.L2.isL2Network && ( + { data.tx_burnt_fee && !config.features.rollup.isEnabled && ( ) } - { appConfig.L2.isL2Network && ( + { config.features.rollup.isEnabled && ( <> { data.l1_gas_used && ( { hint="L1 gas price" isLoading={ isPlaceholderData } > - { BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { appConfig.network.currency.symbol } + { BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { config.chain.currency.symbol } ({ BigNumber(data.l1_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } Gwei) ) } @@ -399,7 +399,7 @@ const TxDetails = () => { > diff --git a/ui/tx/details/TxDetailsAction.tsx b/ui/tx/details/TxDetailsAction.tsx index 5246221a2e..9e0759e7a6 100644 --- a/ui/tx/details/TxDetailsAction.tsx +++ b/ui/tx/details/TxDetailsAction.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { TxAction, TxActionGeneral } from 'types/api/txAction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import uniswapIcon from 'icons/uniswap.svg'; import AddressLink from 'ui/shared/address/AddressLink'; import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet'; @@ -39,15 +39,15 @@ const TxDetailsAction = ({ action }: Props) => { const amount1 = BigNumber(data.amount1).toFormat(); const [ text0, text1 ] = getActionText(type); const token0 = { - address: data.symbol0 === 'Ether' ? appConfig.network.currency.address || '' : data.address0, - name: data.symbol0 === 'Ether' ? appConfig.network.currency.symbol || null : data.symbol0, + address: data.symbol0 === 'Ether' ? '' : data.address0, + name: data.symbol0 === 'Ether' ? config.chain.currency.symbol || null : data.symbol0, type: 'ERC-20', symbol: null, icon_url: null, }; const token1 = { - address: data.symbol1 === 'Ether' ? appConfig.network.currency.address || '' : data.address1, - name: data.symbol1 === 'Ether' ? appConfig.network.currency.symbol || null : data.symbol1, + address: data.symbol1 === 'Ether' ? '' : data.address1, + name: data.symbol1 === 'Ether' ? config.chain.currency.symbol || null : data.symbol1, type: 'ERC-20', symbol: null, icon_url: null, diff --git a/ui/tx/internals/TxInternalsListItem.tsx b/ui/tx/internals/TxInternalsListItem.tsx index db66a6cbee..c3a713643d 100644 --- a/ui/tx/internals/TxInternalsListItem.tsx +++ b/ui/tx/internals/TxInternalsListItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { InternalTransaction } from 'types/api/internalTransaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import eastArrowIcon from 'icons/arrows/east.svg'; import Address from 'ui/shared/address/Address'; import AddressIcon from 'ui/shared/address/AddressIcon'; @@ -44,9 +44,9 @@ const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit: ) } - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } - { BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() } + { BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() } diff --git a/ui/tx/internals/TxInternalsTable.tsx b/ui/tx/internals/TxInternalsTable.tsx index 7f4fa646d6..2fea20d782 100644 --- a/ui/tx/internals/TxInternalsTable.tsx +++ b/ui/tx/internals/TxInternalsTable.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { InternalTransaction } from 'types/api/internalTransaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import arrowIcon from 'icons/arrows/east.svg'; import { default as Thead } from 'ui/shared/TheadSticky'; import TxInternalsTableItem from 'ui/tx/internals/TxInternalsTableItem'; @@ -31,13 +31,13 @@ const TxInternalsTable = ({ data, sort, onSortToggle, top, isLoading }: Props) = { sort?.includes('value') && } - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } { sort?.includes('gas-limit') && } - Gas limit { appConfig.network.currency.symbol } + Gas limit { config.chain.currency.symbol } diff --git a/ui/tx/internals/TxInternalsTableItem.tsx b/ui/tx/internals/TxInternalsTableItem.tsx index ff9817df63..4cbaa424c2 100644 --- a/ui/tx/internals/TxInternalsTableItem.tsx +++ b/ui/tx/internals/TxInternalsTableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { InternalTransaction } from 'types/api/internalTransaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import Address from 'ui/shared/address/Address'; import AddressIcon from 'ui/shared/address/AddressIcon'; @@ -56,7 +56,7 @@ const TxInternalTableItem = ({ type, from, to, value, success, error, gas_limit: - { BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() } + { BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() } diff --git a/ui/tx/state/utils.tsx b/ui/tx/state/utils.tsx index b2921604eb..7d727b57e3 100644 --- a/ui/tx/state/utils.tsx +++ b/ui/tx/state/utils.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { TxStateChange } from 'types/api/txStateChanges'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { ZERO_ADDRESS } from 'lib/consts'; import { nbsp, space } from 'lib/html-entities'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; @@ -50,8 +50,8 @@ export function getStateElements(data: TxStateChange, isLoading?: boolean) { switch (data.type) { case 'coin': { - const beforeBn = BigNumber(data.balance_before || '0').div(10 ** appConfig.network.currency.decimals); - const afterBn = BigNumber(data.balance_after || '0').div(10 ** appConfig.network.currency.decimals); + const beforeBn = BigNumber(data.balance_before || '0').div(10 ** config.chain.currency.decimals); + const afterBn = BigNumber(data.balance_after || '0').div(10 ** config.chain.currency.decimals); const differenceBn = afterBn.minus(beforeBn); const changeColor = beforeBn.lte(afterBn) ? 'green.500' : 'red.500'; const changeSign = beforeBn.lte(afterBn) ? '+' : '-'; @@ -59,12 +59,12 @@ export function getStateElements(data: TxStateChange, isLoading?: boolean) { return { before: ( - { beforeBn.toFormat() } { appConfig.network.currency.symbol } + { beforeBn.toFormat() } { config.chain.currency.symbol } ), after: ( - { afterBn.toFormat() } { appConfig.network.currency.symbol } + { afterBn.toFormat() } { config.chain.currency.symbol } ), change: ( diff --git a/ui/txs/TxAdditionalInfoContent.tsx b/ui/txs/TxAdditionalInfoContent.tsx index 09d6f3feeb..ab1568e8df 100644 --- a/ui/txs/TxAdditionalInfoContent.tsx +++ b/ui/txs/TxAdditionalInfoContent.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { Transaction } from 'types/api/transaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import getValueWithUnit from 'lib/getValueWithUnit'; import CurrencyValue from 'ui/shared/CurrencyValue'; import LinkInternal from 'ui/shared/LinkInternal'; @@ -34,7 +34,7 @@ const TxAdditionalInfoContent = ({ tx }: { tx: Transaction }) => { diff --git a/ui/txs/TxsListItem.tsx b/ui/txs/TxsListItem.tsx index 2ceab54c2b..e4c34864dc 100644 --- a/ui/txs/TxsListItem.tsx +++ b/ui/txs/TxsListItem.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { Transaction } from 'types/api/transaction'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import transactionIcon from 'icons/transactions.svg'; import getValueWithUnit from 'lib/getValueWithUnit'; @@ -142,11 +142,11 @@ const TxsListItem = ({ tx, isLoading, showBlockInfo, currentAddress, enableTimeI ) : '-' } - Value { appConfig.network.currency.symbol } + Value { config.chain.currency.symbol } { getValueWithUnit(tx.value).toFormat() } - Fee { appConfig.network.currency.symbol } + Fee { config.chain.currency.symbol } { getValueWithUnit(tx.fee.value).toFormat() } diff --git a/ui/txs/TxsTable.tsx b/ui/txs/TxsTable.tsx index b8b3f40fb5..b030dcce21 100644 --- a/ui/txs/TxsTable.tsx +++ b/ui/txs/TxsTable.tsx @@ -5,7 +5,7 @@ import React from 'react'; import type { Transaction } from 'types/api/transaction'; import type { Sort } from 'types/client/txs-sort'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import rightArrowIcon from 'icons/arrows/east.svg'; import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import TheadSticky from 'ui/shared/TheadSticky'; @@ -55,14 +55,14 @@ const TxsTable = ({ { sorting === 'val-asc' && } { sorting === 'val-desc' && } - { `Value ${ appConfig.network.currency.symbol }` } + { `Value ${ config.chain.currency.symbol }` } { sorting === 'fee-asc' && } { sorting === 'fee-desc' && } - { `Fee ${ appConfig.network.currency.symbol }` } + { `Fee ${ config.chain.currency.symbol }` } diff --git a/ui/verifiedContracts/VerifiedContractsListItem.tsx b/ui/verifiedContracts/VerifiedContractsListItem.tsx index 719cfc9b8a..69aad721c7 100644 --- a/ui/verifiedContracts/VerifiedContractsListItem.tsx +++ b/ui/verifiedContracts/VerifiedContractsListItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { VerifiedContract } from 'types/api/contracts'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconCheck from 'icons/check.svg'; import iconCross from 'icons/cross.svg'; import iconSuccess from 'icons/status/success.svg'; @@ -24,7 +24,7 @@ interface Props { const VerifiedContractsListItem = ({ data, isLoading }: Props) => { const balance = data.coin_balance && data.coin_balance !== '0' ? - BigNumber(data.coin_balance).div(10 ** appConfig.network.currency.decimals).dp(6).toFormat() : + BigNumber(data.coin_balance).div(10 ** config.chain.currency.decimals).dp(6).toFormat() : '0'; return ( @@ -38,7 +38,7 @@ const VerifiedContractsListItem = ({ data, isLoading }: Props) => { - Balance { appConfig.network.currency.symbol } + Balance { config.chain.currency.symbol } { balance } diff --git a/ui/verifiedContracts/VerifiedContractsTable.tsx b/ui/verifiedContracts/VerifiedContractsTable.tsx index 9852b6e4b7..e485616dd4 100644 --- a/ui/verifiedContracts/VerifiedContractsTable.tsx +++ b/ui/verifiedContracts/VerifiedContractsTable.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { VerifiedContract } from 'types/api/contracts'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import arrowIcon from 'icons/arrows/east.svg'; import { default as Thead } from 'ui/shared/TheadSticky'; @@ -28,7 +28,7 @@ const VerifiedContractsTable = ({ data, sort, onSortToggle, isLoading }: Props) { sort?.includes('balance') && } - Balance { appConfig.network.currency.symbol } + Balance { config.chain.currency.symbol } diff --git a/ui/verifiedContracts/VerifiedContractsTableItem.tsx b/ui/verifiedContracts/VerifiedContractsTableItem.tsx index dfe4ed0112..657b629d0d 100644 --- a/ui/verifiedContracts/VerifiedContractsTableItem.tsx +++ b/ui/verifiedContracts/VerifiedContractsTableItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { VerifiedContract } from 'types/api/contracts'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import iconCheck from 'icons/check.svg'; import iconCross from 'icons/cross.svg'; import iconSuccess from 'icons/status/success.svg'; @@ -22,7 +22,7 @@ interface Props { const VerifiedContractsTableItem = ({ data, isLoading }: Props) => { const balance = data.coin_balance && data.coin_balance !== '0' ? - BigNumber(data.coin_balance).div(10 ** appConfig.network.currency.decimals).dp(6).toFormat() : + BigNumber(data.coin_balance).div(10 ** config.chain.currency.decimals).dp(6).toFormat() : '0'; return ( diff --git a/ui/watchlist/AddressModal/AddressFormNotifications.tsx b/ui/watchlist/AddressModal/AddressFormNotifications.tsx index b49953caa2..6b3b94d329 100644 --- a/ui/watchlist/AddressModal/AddressFormNotifications.tsx +++ b/ui/watchlist/AddressModal/AddressFormNotifications.tsx @@ -3,12 +3,12 @@ import React, { useCallback } from 'react'; import { Controller } from 'react-hook-form'; import type { Path, ControllerRenderProps, FieldValues, Control } from 'react-hook-form'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import CheckboxInput from 'ui/shared/CheckboxInput'; // does it depend on the network? const NOTIFICATIONS = [ 'native', 'ERC-20', 'ERC-721' ] as const; -const NOTIFICATIONS_NAMES = [ appConfig.network.currency.symbol, 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ]; +const NOTIFICATIONS_NAMES = [ config.chain.currency.symbol, 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ]; type Props = { control: Control; diff --git a/ui/watchlist/WatchlistTable/WatchListAddressItem.tsx b/ui/watchlist/WatchlistTable/WatchListAddressItem.tsx index 17a0770418..67d785c8ca 100644 --- a/ui/watchlist/WatchlistTable/WatchListAddressItem.tsx +++ b/ui/watchlist/WatchlistTable/WatchListAddressItem.tsx @@ -4,7 +4,7 @@ import React from 'react'; import type { WatchlistAddress } from 'types/api/account'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import TokensIcon from 'icons/tokens.svg'; import WalletIcon from 'icons/wallet.svg'; import getCurrencyValue from 'lib/getCurrencyValue'; @@ -18,8 +18,7 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL const infoItemsPaddingLeft = { base: 1, lg: 8 }; const nativeTokenData = React.useMemo(() => ({ - address: appConfig.network.currency.address || '', - name: appConfig.network.currency.name || '', + name: config.chain.currency.name || '', icon_url: '', }), [ ]); @@ -29,21 +28,19 @@ const WatchListAddressItem = ({ item, isLoading }: { item: WatchlistAddress; isL - { appConfig.network.currency.address && ( - - ) } + - { appConfig.network.currency.symbol } balance: + { config.chain.currency.symbol } balance: diff --git a/ui/withdrawals/WithdrawalsListItem.tsx b/ui/withdrawals/WithdrawalsListItem.tsx index d2c167b36a..11dcc745cb 100644 --- a/ui/withdrawals/WithdrawalsListItem.tsx +++ b/ui/withdrawals/WithdrawalsListItem.tsx @@ -6,7 +6,7 @@ import type { AddressWithdrawalsItem } from 'types/api/address'; import type { BlockWithdrawalsItem } from 'types/api/block'; import type { WithdrawalsItem } from 'types/api/withdrawals'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import blockIcon from 'icons/block.svg'; import dayjs from 'lib/date/dayjs'; import Address from 'ui/shared/address/Address'; @@ -85,7 +85,7 @@ const WithdrawalsListItem = ({ item, isLoading, view }: Props) => { Value - + ) } diff --git a/ui/withdrawals/WithdrawalsTable.tsx b/ui/withdrawals/WithdrawalsTable.tsx index 0b6d7b0b89..882d8eff3d 100644 --- a/ui/withdrawals/WithdrawalsTable.tsx +++ b/ui/withdrawals/WithdrawalsTable.tsx @@ -5,7 +5,7 @@ import type { AddressWithdrawalsItem } from 'types/api/address'; import type { BlockWithdrawalsItem } from 'types/api/block'; import type { WithdrawalsItem } from 'types/api/withdrawals'; -import appConfig from 'configs/app/config'; +import config from 'configs/app'; import { default as Thead } from 'ui/shared/TheadSticky'; import WithdrawalsTableItem from './WithdrawalsTableItem'; @@ -34,7 +34,7 @@ const WithdrawalsTable = ({ items, isLoading, top, view = 'list' }: Props) => { { view !== 'block' && Block } { view !== 'address' && To } { view !== 'block' && Age } - { `Value ${ appConfig.beaconChain.currencySymbol }` } + { `Value ${ config.features.beaconChain.currency.symbol }` }