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
This commit is contained in:
tom goriunov
2023-08-09 15:39:36 -04:00
committed by GitHub
parent 6be583b3c0
commit f644f2a96e
180 changed files with 2653 additions and 1021 deletions
+2 -2
View File
@@ -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 ],
+16
View File
@@ -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 .
+23
View File
@@ -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;
+23
View File
@@ -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;
+19
View File
@@ -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;
-213
View File
@@ -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 = <T extends string>(env: T | undefined): T | undefined => env?.replaceAll('\'', '"') as T;
const parseEnvJson = <DataType>(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<WalletType> = [
'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<AdBannerProviders> = [ '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<AdTextProviders> = [ '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<Array<NetworkExplorer>>(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<Array<NavItemExternal>>(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<AdButlerConfig>(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP)),
adButlerConfigMobile: parseEnvJson<AdButlerConfig>(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<Array<ChainIndicatorId>>(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;
+33
View File
@@ -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,
});
@@ -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: '',
},
});
+23
View File
@@ -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<AdBannerProviders> = [ '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<AdButlerConfig>(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP)) ?? undefined,
mobile: parseEnvJson<AdButlerConfig>(getEnvValue(process.env.NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE)) ?? undefined,
},
},
});
+16
View File
@@ -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,
});
+9
View File
@@ -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),
},
});
@@ -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 ?? '',
},
});
+11
View File
@@ -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 ?? '',
},
});
+9
View File
@@ -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,
});
+9
View File
@@ -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,
});
+18
View File
@@ -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';
+12
View File
@@ -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 ?? '',
});
+9
View File
@@ -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 ?? '',
});
+9
View File
@@ -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,
});
+8
View File
@@ -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) ?? '',
});
+13
View File
@@ -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),
});
+12
View File
@@ -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: '',
},
});
+12
View File
@@ -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: '',
},
});
+12
View File
@@ -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: '',
},
});
+23
View File
@@ -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<WalletType> = [
'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: {},
});
+17
View File
@@ -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;
+7
View File
@@ -0,0 +1,7 @@
import { getEnvValue } from './utils';
export default Object.freeze({
reCaptcha: {
siteKey: getEnvValue(process.env.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY),
},
});
+45
View File
@@ -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<Array<NavItemExternal>>(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<Array<ChainIndicatorId>>(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<Array<NetworkExplorer>>(getEnvValue(process.env.NEXT_PUBLIC_NETWORK_EXPLORERS)) || [],
},
});
export default UI;
+9
View File
@@ -0,0 +1,9 @@
export const getEnvValue = <T extends string>(env: T | undefined): T | undefined => env?.replaceAll('\'', '"') as T;
export const parseEnvJson = <DataType>(env: string | undefined): DataType | null => {
try {
return JSON.parse(env || 'null') as DataType | null;
} catch (error) {
return null;
}
};
+22 -20
View File
@@ -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
+26 -21
View File
@@ -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_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli
NEXT_PUBLIC_IS_TESTNET=true
# 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_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
NEXT_PUBLIC_API_HOST=eth-goerli.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
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
+32 -27
View File
@@ -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
# 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
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=
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_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json
NEXT_PUBLIC_IS_L2_NETWORK=false
# network config
# 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_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
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111
NEXT_PUBLIC_IS_TESTNET=true
# api config
# api configuration
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_API_BASE_PATH=/
# ui config
## 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_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_LOGO_DARK=
NEXT_PUBLIC_NETWORK_ICON=
NEXT_PUBLIC_NETWORK_ICON_DARK=
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
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
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=/
+21 -15
View File
@@ -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
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
+27 -22
View File
@@ -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_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_IS_TESTNET=true
# 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_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
NEXT_PUBLIC_API_HOST=blockscout-main.k8s-dev.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/
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
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com
+28 -24
View File
@@ -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
NEXT_PUBLIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
+26 -20
View File
@@ -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
+33 -28
View File
@@ -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
# 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
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=
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_MARKETPLACE_CONFIG_URL=https://localhost:3000/marketplace-config.json
NEXT_PUBLIC_IS_L2_NETWORK=false
NEXT_PUBLIC_AD_BANNER_PROVIDER=slise
# network config
# 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_TOKEN_ADDRESS=
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form
# api config
# api configuration
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_API_BASE_PATH=/
# ui config
## 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_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_LOGO_DARK=
NEXT_PUBLIC_NETWORK_ICON=
NEXT_PUBLIC_NETWORK_ICON_DARK=
## 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
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
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=/
+6 -4
View File
@@ -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);
}
+4 -1
View File
@@ -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 "$@"
+5 -3
View File
@@ -64,11 +64,13 @@ async function checkPlaceholdersCongruity(runTimeEnvs: Record<string, string>) {
}
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();
}
+3
View File
@@ -0,0 +1,3 @@
/node_modules
/build
index.js
+6
View File
@@ -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
+23
View File
@@ -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();
}
@@ -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"
}
}
@@ -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,
}
}
@@ -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),
},
};
File diff suppressed because it is too large Load Diff
@@ -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
-2
View File
@@ -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
@@ -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:
-2
View File
@@ -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:
+1 -1
View File
@@ -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
+315 -116
View File
@@ -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 |
&nbsp;
## App configuration
| 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_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` |
&nbsp;
## Blockchain parameters
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| 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_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` |
&nbsp;
## 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` |
&nbsp;
## UI configuration
### 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` |
&nbsp;
### 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_IS_TESTNET | `boolean`| Set to true if network is testnet | - | `false` | `true` |
## UI configuration
| Variable | Type| Description | Is required | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| 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` |
&nbsp;
### 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'}]` |
&nbsp;
### Misc
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_NETWORK_EXPLORERS | `Array<NetworkExplorer>` 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 `<baseUrl><paths[<entity-type>]><entity-id>`, e.g `https://explorer.anyblock.tools/ethereum/poa/core/tx/<tx-id>`
&nbsp;
## 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 | - | `<your-secret>` |
| 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` |
&nbsp;
### 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` |
&nbsp;
### 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 | - | `<your-secret>` |
| 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` |
&nbsp;
### 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<MarketplaceCategoryId>` | 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'` |
&nbsp;
### 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` |
&nbsp;
### 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` |
&nbsp;
### 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` |
&nbsp;
### 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 | - | `<your-secret>` |
&nbsp;
### 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` |
&nbsp;
### 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 | - | `<your-secret>` |
&nbsp;
### 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` |
&nbsp;
### 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` |
&nbsp;
### 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<MarketplaceCategoryId>` | 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
&nbsp;
| Variable | Type| Description | Is required | Default value | Example value |
### Solidity to UML diagrams
| Variable | Type| Description | Compulsoriness | 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` |
| NEXT_PUBLIC_VISUALIZE_API_HOST | `string` | Visualize API endpoint url | Required | - | `https://visualizer.services.blockscout.com` |
### Network explorer configuration properties
&nbsp;
| Variable | Type| Description | Is required | Default value | Example value |
### Blockchain statistics
| 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_STATS_API_HOST | `string` | API endpoint url | Required | - | `https://stats.services.blockscout.com` |
*Note* The url of an entity will be constructed as `<baseUrl><paths[<entity-type>]><entity-id>`, e.g `https://explorer.anyblock.tools/ethereum/poa/core/tx/<tx-id>`
&nbsp;
### Footer links configuration properties
### Web3 wallet integration (add token or network to the wallet)
| Variable | Type| Description | Is required | Default value | Example value |
This feature is **enabled by default** with the `metamask` wallet type. To switch it off pass `NEXT_PUBLIC_WEB3_DEFAULT_WALLET=none`.
| 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_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` |
## Account configuration
&nbsp;
In order to enable "My Account" feature you have to configure following set of variables. All variables are **required**.
### Verified tokens info
| Variable | Type| Description | Is required | Default value | Example value |
| Variable | Type| Description | Compulsoriness | 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 | - | `<secret>` |
| 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` |
| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | Required | - | `https://contracts-info.services.blockscout.com` |
## App configuration
&nbsp;
| Variable | Type| Description | Is required | Default value | Example value |
### Sentry error monitoring
| 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` |
## API configuration
| Variable | Type| Description | Is required | 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_SENTRY_DSN | `string` | Client key for your Sentry.io app | Required | - | `<your-secret>` |
| SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `<your-secret>` |
| 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` |
&nbsp;
## External services configuration
| Variable | Type| Description | Is required | Default value | Example value |
### Google ReCaptcha
For obtaining the variables values please refer to [reCAPTCHA documentation](https://developers.google.com/recaptcha).
| Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_SENTRY_DSN | `string` | Client key for your Sentry.io app | - | - | `<secret>` |
| SENTRY_CSP_REPORT_URI | `string` | URL for sending CSP-reports to your Sentry.io app | - | - | `<secret>` |
| NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID | `string` | Project id for [WalletConnect](https://docs.walletconnect.com/2.0/web3modal/react/installation#obtain-project-id) integration | - | - | `<secret>` |
| NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY | `string` | Site key for [reCAPTCHA](https://developers.google.com/recaptcha) service | - | - | `<secret>` |
| 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 | - | - | `<secret>` |
## 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` |
## Beacon chain configuration
| Variable | Type| Description | Is required | 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 | - | - | `<your-secret>` |
+3 -3
View File
@@ -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<R extends ResourceName>(
queryParams?: Record<string, string | Array<string> | 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);
+3 -3
View File
@@ -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<string, string | number | undefined>,
) {
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);
+3 -3
View File
@@ -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;
}
+19 -19
View File
@@ -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',
+2 -2
View File
@@ -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,
},
+16 -17
View File
@@ -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,
],
} : {}),
};
+2 -2
View File
@@ -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 {};
}
+2 -2
View File
@@ -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 {};
}
+2 -2
View File
@@ -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 {};
}
+2 -2
View File
@@ -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 {};
}
+2 -2
View File
@@ -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;
}
+3 -3
View File
@@ -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 }: <Issue Title>`;
const title = `${ config.chain.name }: <Issue Title>`;
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
+2 -2
View File
@@ -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 } });
}
+12 -15
View File
@@ -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<NavItem> = [
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 ]);
}
+2 -2
View File
@@ -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<R extends Route>(route: R, apiData?: ApiData<R>
const params = {
...route.query,
...apiData,
network_name: appConfig.network.name,
network_name: config.chain.name,
network_title: getNetworkTitle(),
};
+2 -2
View File
@@ -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<boolean> {
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));
+2 -2
View File
@@ -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<EventType extends EventTypes>(
optionsOrCallback?: TrackFnArgs[2],
callback?: TrackFnArgs[3],
) {
if (!appConfig.mixpanel.projectToken) {
if (!config.features.mixpanel.isEnabled) {
return;
}
mixpanel.track(type, properties, optionsOrCallback, callback);
+6 -6
View File
@@ -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<Config> = {
const mixpanelConfig: Partial<Config> = {
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,
+2 -2
View File
@@ -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;
}
+2 -2
View File
@@ -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';
}
+2 -2
View File
@@ -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';
}
+2 -2
View File
@@ -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<NetworkExplorer> = (() => {
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)),
+9 -9
View File
@@ -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<Props> = async({ req, query }) => {
};
export const account: GetServerSideProps<Props> = async(context) => {
if (!appConfig.account.isEnabled) {
if (!config.features.account.isEnabled) {
return {
notFound: true,
};
@@ -35,7 +35,7 @@ export const account: GetServerSideProps<Props> = async(context) => {
};
export const verifiedAddresses: GetServerSideProps<Props> = 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<Props> = async(context) => {
};
export const beaconChain: GetServerSideProps<Props> = async(context) => {
if (!appConfig.beaconChain.hasBeaconChain) {
if (!config.features.beaconChain.isEnabled) {
return {
notFound: true,
};
@@ -55,7 +55,7 @@ export const beaconChain: GetServerSideProps<Props> = async(context) => {
};
export const L2: GetServerSideProps<Props> = async(context) => {
if (!appConfig.L2.isL2Network) {
if (!config.features.rollup.isEnabled) {
return {
notFound: true,
};
@@ -65,7 +65,7 @@ export const L2: GetServerSideProps<Props> = async(context) => {
};
export const marketplace: GetServerSideProps<Props> = 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<Props> = async(context) => {
};
export const apiDocs: GetServerSideProps<Props> = async(context) => {
if (!appConfig.apiDoc.specUrl) {
if (!config.features.restApiDocs.isEnabled) {
return {
notFound: true,
};
@@ -85,7 +85,7 @@ export const apiDocs: GetServerSideProps<Props> = async(context) => {
};
export const csvExport: GetServerSideProps<Props> = async(context) => {
if (!appConfig.reCaptcha.siteKey) {
if (!config.features.csvExport.isEnabled) {
return {
notFound: true,
};
@@ -95,7 +95,7 @@ export const csvExport: GetServerSideProps<Props> = async(context) => {
};
export const stats: GetServerSideProps<Props> = async(context) => {
if (!appConfig.statsApi.endpoint) {
if (!config.features.stats.isEnabled) {
return {
notFound: true,
};
+6 -6
View File
@@ -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,
+4 -4
View File
@@ -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<WindowProvider>();
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);
}
});
+1 -1
View File
@@ -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<WalletType, WalletInfo> = {
export const WALLETS_INFO: Record<Exclude<WalletType, 'none'>, WalletInfo> = {
metamask: {
name: 'MetaMask',
icon: metamaskIcon,
+2 -2
View File
@@ -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) {
<AppContextProvider pageProps={ pageProps }>
<QueryClientProvider client={ queryClient }>
<ScrollDirectionProvider>
<SocketProvider url={ `${ appConfig.api.socket }${ appConfig.api.basePath }/socket/v2` }>
<SocketProvider url={ `${ config.api.socket }${ config.api.basePath }/socket/v2` }>
<Component { ...pageProps }/>
</SocketProvider>
</ScrollDirectionProvider>
+3 -3
View File
@@ -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."
/>
<meta property="og:image" content={ appConfig.app.baseUrl + '/static/og.png' }/>
<meta property="og:image" content={ config.app.baseUrl + '/static/og.png' }/>
<meta property="og:site_name" content="Blockscout"/>
<meta property="og:type" content="website"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta property="twitter:image" content={ appConfig.app.baseUrl + '/static/og_twitter.png' }/>
<meta property="twitter:image" content={ config.app.baseUrl + '/static/og_twitter.png' }/>
</Head>
<body>
<ColorModeScript initialColorMode={ theme.config.initialColorMode }/>
+2 -2
View File
@@ -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(),
+1 -1
View File
@@ -1,4 +1,4 @@
export type WalletType = 'metamask' | 'coinbase';
export type WalletType = 'metamask' | 'coinbase' | 'none';
export interface WalletInfo {
name: string;
+32 -11
View File
@@ -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;
}
+2 -2
View File
@@ -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) => {
<Th width="17%">Age</Th>
<Th width="16%">Txn</Th>
<Th width="25%">Gas used</Th>
<Th width="25%" isNumeric>Reward { appConfig.network.currency.symbol }</Th>
<Th width="25%" isNumeric>Reward { config.chain.currency.symbol }</Th>
</Tr>
</Thead>
<Tbody>
+2 -2
View File
@@ -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;
}
@@ -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) => {
/>
</Flex>
<Flex columnGap={ 2 } w="100%">
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Reward { appConfig.network.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 500 } flexShrink={ 0 }>Reward { config.chain.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !props.isLoading } color="text_secondary">{ totalReward.toFixed() }</Skeleton>
</Flex>
</ListItemMobile>
@@ -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 }
/>
);
};
@@ -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) => {
<Th width="20%">Block</Th>
<Th width="20%">Txn</Th>
<Th width="20%">Age</Th>
<Th width="20%" isNumeric pr={ 1 }>Balance { appConfig.network.currency.symbol }</Th>
<Th width="20%" isNumeric pr={ 1 }>Balance { config.chain.currency.symbol }</Th>
<Th width="20%" isNumeric>Delta</Th>
</Tr>
</Thead>
@@ -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) => {
<ListItemMobile rowGap={ 2 } isAnimated>
<Flex justifyContent="space-between" w="100%">
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 600 }>
{ BigNumber(props.value).div(WEI).dp(8).toFormat() } { appConfig.network.currency.symbol }
{ BigNumber(props.value).div(WEI).dp(8).toFormat() } { config.chain.currency.symbol }
</Skeleton>
<Skeleton isLoaded={ !props.isLoading }>
<Stat flexGrow="0">
@@ -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');
@@ -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';
+3 -3
View File
@@ -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) {
+5 -6
View File
@@ -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 (
<DetailsInfoItem
title="Balance"
hint={ `Address balance in ${ appConfig.network.currency.symbol }. Doesn't include ERC20, ERC721 and ERC1155 tokens` }
hint={ `Address balance in ${ config.chain.currency.symbol }. Doesn't include ERC20, ERC721 and ERC1155 tokens` }
flexWrap="nowrap"
alignItems="flex-start"
isLoading={ isLoading }
@@ -88,8 +87,8 @@ const AddressBalance = ({ data, isLoading }: Props) => {
<CurrencyValue
value={ data.coin_balance || '0' }
exchangeRate={ data.exchange_rate }
decimals={ String(appConfig.network.currency.decimals) }
currency={ appConfig.network.currency.symbol }
decimals={ String(config.chain.currency.decimals) }
currency={ config.chain.currency.symbol }
accuracyUsd={ 2 }
accuracy={ 8 }
flexWrap="wrap"
@@ -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 eastArrowIcon from 'icons/arrows/east.svg';
import dayjs from 'lib/date/dayjs';
import Address from 'ui/shared/address/Address';
@@ -79,9 +79,9 @@ const TxInternalsListItem = ({
) }
</Box>
<HStack spacing={ 3 }>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Value { config.chain.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary" minW={ 6 }>
<span>{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }</span>
<span>{ BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() }</span>
</Skeleton>
</HStack>
</ListItemMobile>
+2 -2
View File
@@ -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) => {
<Th width="48px" px={ 0 }/>
<Th width="20%">To</Th>
<Th width="20%" isNumeric>
Value { appConfig.network.currency.symbol }
Value { config.chain.currency.symbol }
</Th>
</Tr>
</Thead>
@@ -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 = ({
</Td>
<Td isNumeric verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block" minW={ 6 }>
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
{ BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() }
</Skeleton>
</Td>
</Tr>
+4 -4
View File
@@ -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 }
/>
<TokenBalancesItem
name={ `${ appConfig.network.currency.symbol } Balance` }
value={ (!nativeUsd.eq(ZERO) ? `$${ nativeUsd.toFormat(2) } USD | ` : '') + `${ nativeValue } ${ appConfig.network.currency.symbol }` }
name={ `${ config.chain.currency.symbol } Balance` }
value={ (!nativeUsd.eq(ZERO) ? `$${ nativeUsd.toFormat(2) } USD | ` : '') + `${ nativeValue } ${ config.chain.currency.symbol }` }
isLoading={ addressQuery.isLoading || tokenQuery.isLoading }
/>
<TokenBalancesItem
@@ -12,7 +12,7 @@ import type {
RootFields,
} from '../types';
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 LinkInternal from 'ui/shared/LinkInternal';
@@ -49,7 +49,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
};
const response = await apiFetch<'address_verification', AddressCheckResponseSuccess, AddressVerificationResponseError>('address_verification', {
fetchParams: { method: 'POST', body },
pathParams: { chainId: appConfig.network.id, type: ':prepare' },
pathParams: { chainId: config.chain.id, type: ':prepare' },
});
if (response.status !== 'SUCCESS') {
@@ -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') {

Some files were not shown because too many files have changed in this diff Show More