Commit 751e2e36 authored by tom goriunov's avatar tom goriunov Committed by GitHub

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
parent c9bc73e1
...@@ -211,7 +211,7 @@ module.exports = { ...@@ -211,7 +211,7 @@ module.exports = {
object: 'process', object: 'process',
property: 'env', property: 'env',
// FIXME: restrict the rule only NEXT_PUBLIC variables // 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', 'react/jsx-key': 'error',
...@@ -289,7 +289,7 @@ module.exports = { ...@@ -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: { rules: {
// for configs allow to consume env variables from process.env directly // for configs allow to consume env variables from process.env directly
'no-restricted-properties': [ 0 ], 'no-restricted-properties': [ 0 ],
......
...@@ -12,6 +12,14 @@ COPY package.json yarn.lock ./ ...@@ -12,6 +12,14 @@ COPY package.json yarn.lock ./
RUN apk add git RUN apk add git
RUN yarn --frozen-lockfile 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 ### ENV VARIABLES CHECKER
# Install dependencies # Install dependencies
WORKDIR /envs-validator WORKDIR /envs-validator
...@@ -52,6 +60,13 @@ RUN ./make_envs_template.sh ./docs/ENVS.md ...@@ -52,6 +60,13 @@ RUN ./make_envs_template.sh ./docs/ENVS.md
RUN yarn build 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 ### ENV VARIABLES CHECKER
# Copy dependencies and source code, then build # Copy dependencies and source code, then build
WORKDIR /envs-validator WORKDIR /envs-validator
...@@ -81,6 +96,7 @@ COPY --from=builder /app/next.config.js ./ ...@@ -81,6 +96,7 @@ COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/package.json ./package.json
COPY --from=builder /envs-validator/index.js ./envs-validator.js 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 scripts and ENVs file
COPY --chmod=+x ./deploy/scripts/entrypoint.sh . COPY --chmod=+x ./deploy/scripts/entrypoint.sh .
......
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;
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;
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;
/* 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;
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,
});
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: '',
},
});
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,
},
},
});
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,
});
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),
},
});
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 ?? '',
},
});
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 ?? '',
},
});
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,
});
import { getEnvValue } from '../utils';
const defaultTxHash = getEnvValue(process.env.NEXT_PUBLIC_GRAPHIQL_TRANSACTION);
export default Object.freeze({
title: 'GraphQL API documentation',
isEnabled: true,
defaultTxHash,
});
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';
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 ?? '',
});
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 ?? '',
});
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,
});
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) ?? '',
});
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),
});
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: '',
},
});
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: '',
},
});
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: '',
},
});
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: {},
});
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;
import { getEnvValue } from './utils';
export default Object.freeze({
reCaptcha: {
siteKey: getEnvValue(process.env.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY),
},
});
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;
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;
}
};
# Set of ENVs for Ethereum network explorer # Set of ENVs for Ethereum network explorer
# https://eth.blockscout.com/ # https://eth.blockscout.com/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 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_NAME=Ethereum
NEXT_PUBLIC_NETWORK_SHORT_NAME=ETH NEXT_PUBLIC_NETWORK_SHORT_NAME=ETH
NEXT_PUBLIC_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_ICON=
NEXT_PUBLIC_NETWORK_ID=1 NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 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_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://eth.llamarpc.com 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_HOST=eth.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ 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_STATS_API_HOST=https://stats-eth-main.k8s.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
......
# Set of ENVs for Goerli testnet network explorer # Set of ENVs for Goerli testnet network explorer
# https://eth-goerli.blockscout.com/ # https://eth-goerli.blockscout.com/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
# ui config # blockchain parameters
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
NEXT_PUBLIC_NETWORK_NAME=Goerli NEXT_PUBLIC_NETWORK_NAME=Goerli
NEXT_PUBLIC_NETWORK_SHORT_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_ID=5
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli 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 NEXT_PUBLIC_IS_TESTNET=true
# api config # api configuration
NEXT_PUBLIC_API_HOST=eth-goerli.blockscout.com NEXT_PUBLIC_API_HOST=eth-goerli.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_BASE_PATH=/
# ui config
## homepage
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
## sidebar
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg
## footer
## misc
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
......
# Set of ENVs for Jest unit tests # Set of ENVs for Jest unit tests
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_INSTANCE=jest
NEXT_PUBLIC_APP_ENV=testing # blockchain parameters
NEXT_PUBLIC_NETWORK_NAME=Blockscout
NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout
NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111
NEXT_PUBLIC_IS_TESTNET=true
# api configuration
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_API_BASE_PATH=/
# ui config # 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'}}] ## homepage
NEXT_PUBLIC_GIT_TAG=v1.0.11
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap']
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND= NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=
NEXT_PUBLIC_FEATURED_NETWORKS= ## sidebar
NEXT_PUBLIC_FOOTER_LINKS=
NEXT_PUBLIC_NETWORK_LOGO= NEXT_PUBLIC_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_LOGO_DARK= NEXT_PUBLIC_NETWORK_LOGO_DARK=
NEXT_PUBLIC_NETWORK_ICON= NEXT_PUBLIC_NETWORK_ICON=
NEXT_PUBLIC_NETWORK_ICON_DARK= NEXT_PUBLIC_NETWORK_ICON_DARK=
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 NEXT_PUBLIC_FEATURED_NETWORKS=
NEXT_PUBLIC_IS_TESTNET=true ## 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_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_L2_NETWORK=false
# network config
NEXT_PUBLIC_NETWORK_NAME=Blockscout
NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout
NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form
# api config
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004 NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005 NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006 NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
NEXT_PUBLIC_API_BASE_PATH=/
...@@ -2,34 +2,40 @@ ...@@ -2,34 +2,40 @@
# frontend app URL - https://localhost:3000/ # frontend app URL - https://localhost:3000/
# API URL - https://localhost:3001/ # API URL - https://localhost:3001/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 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_NAME=POA
NEXT_PUBLIC_NETWORK_SHORT_NAME=POA NEXT_PUBLIC_NETWORK_SHORT_NAME=POA
NEXT_PUBLIC_NETWORK_ID=99 NEXT_PUBLIC_NETWORK_ID=99
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 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_VERIFICATION_TYPE=validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network
# api config # api configuration
NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=localhost NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PROTOCOL=http 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
# Set of ENVs for Develompent network explorer # Set of ENVs for Develompent network explorer
# https://blockscout-main.k8s-dev.blockscout.com/ # https://blockscout-main.k8s-dev.blockscout.com/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
# ui config # blockchain parameters
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
NEXT_PUBLIC_NETWORK_NAME=Goerli NEXT_PUBLIC_NETWORK_NAME=Goerli
NEXT_PUBLIC_NETWORK_SHORT_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_ID=5
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://rpc.ankr.com/eth_goerli NEXT_PUBLIC_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_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_IS_TESTNET=true NEXT_PUBLIC_IS_TESTNET=true
# api config # api configuration
NEXT_PUBLIC_API_HOST=blockscout-main.k8s-dev.blockscout.com NEXT_PUBLIC_API_HOST=blockscout-main.k8s-dev.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_BASE_PATH=/
# ui config
## homepage
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
## sidebar
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/goerli.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/goerli.svg
## footer
## misc
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
# app features
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_STATS_API_HOST=https://stats-goerli.k8s-dev.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.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_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com
......
# Set of ENVs for Develompent L2 network explorer # Set of ENVs for Develompent L2 network explorer
# https://blockscout-optimism-goerli.k8s-dev.blockscout.com/ # https://blockscout-optimism-goerli.k8s-dev.blockscout.com/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
# ui config # blockchain parameters
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
NEXT_PUBLIC_NETWORK_NAME=Base Göerli NEXT_PUBLIC_NETWORK_NAME=Base Göerli
NEXT_PUBLIC_NETWORK_SHORT_NAME=Base 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_ID=84531
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 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_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://goerli.base.org 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 NEXT_PUBLIC_IS_TESTNET=true
# api config # api configuration
NEXT_PUBLIC_API_HOST=blockscout-optimism-goerli.k8s-dev.blockscout.com NEXT_PUBLIC_API_HOST=blockscout-optimism-goerli.k8s-dev.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ 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_IS_L2_NETWORK=true
NEXT_PUBLIC_L1_BASE_URL=https://blockscout-main.k8s-dev.blockscout.com 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
# Set of ENVs for POA network explorer # Set of ENVs for POA network explorer
# https://blockscout.com/poa/core/ # https://blockscout.com/poa/core/
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3000 NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
# ui config # blockchain parameters
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
NEXT_PUBLIC_NETWORK_NAME=POA NEXT_PUBLIC_NETWORK_NAME=POA
NEXT_PUBLIC_NETWORK_SHORT_NAME=POA NEXT_PUBLIC_NETWORK_SHORT_NAME=POA
NEXT_PUBLIC_NETWORK_ID=99 NEXT_PUBLIC_NETWORK_ID=99
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA NEXT_PUBLIC_NETWORK_CURRENCY_NAME=POA
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=POA
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 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_HOST=blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/poa/core 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
# Set of ENVs for Playwright components tests # Set of ENVs for Playwright components tests
# app config # app configuration
NEXT_PUBLIC_APP_PROTOCOL=http NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_APP_HOST=localhost NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_APP_PORT=3100 NEXT_PUBLIC_APP_PORT=3100
NEXT_PUBLIC_APP_INSTANCE=pw
NEXT_PUBLIC_APP_ENV=testing # blockchain parameters
NEXT_PUBLIC_NETWORK_NAME=Blockscout
NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout
NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
# api configuration
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_API_BASE_PATH=/
# ui config # 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'}}] ## homepage
NEXT_PUBLIC_GIT_TAG=v1.0.11
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap'] NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap']
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND= NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=
## sidebar
NEXT_PUBLIC_FEATURED_NETWORKS= NEXT_PUBLIC_FEATURED_NETWORKS=
NEXT_PUBLIC_FOOTER_LINKS=
NEXT_PUBLIC_NETWORK_LOGO= NEXT_PUBLIC_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_LOGO_DARK= NEXT_PUBLIC_NETWORK_LOGO_DARK=
NEXT_PUBLIC_NETWORK_ICON= NEXT_PUBLIC_NETWORK_ICON=
NEXT_PUBLIC_NETWORK_ICON_DARK= NEXT_PUBLIC_NETWORK_ICON_DARK=
NEXT_PUBLIC_NETWORK_RPC_URL=https://localhost:1111 ## footer
NEXT_PUBLIC_IS_TESTNET=true 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_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_L2_NETWORK=false
NEXT_PUBLIC_AD_BANNER_PROVIDER=slise NEXT_PUBLIC_AD_BANNER_PROVIDER=slise
# network config
NEXT_PUBLIC_NETWORK_NAME=Blockscout
NEXT_PUBLIC_NETWORK_SHORT_NAME=Blockscout
NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS=
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-form
# api config
NEXT_PUBLIC_API_HOST=localhost
NEXT_PUBLIC_API_PORT=3003
NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004 NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005 NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006 NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
NEXT_PUBLIC_API_BASE_PATH=/
import type * as Sentry from '@sentry/react'; import type * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing'; import { BrowserTracing } from '@sentry/tracing';
import appConfig from 'configs/app';
export const config: Sentry.BrowserOptions = { export const config: Sentry.BrowserOptions = {
environment: process.env.NEXT_PUBLIC_APP_ENV || process.env.NODE_ENV, environment: appConfig.features.sentry.environment,
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, dsn: appConfig.features.sentry.dsn,
release: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA, release: process.env.NEXT_PUBLIC_GIT_TAG || process.env.NEXT_PUBLIC_GIT_COMMIT_SHA,
integrations: [ new BrowserTracing() ], integrations: [ new BrowserTracing() ],
// We recommend adjusting this value in production, or using tracesSampler // We recommend adjusting this value in production, or using tracesSampler
// for finer control // for finer control
...@@ -55,5 +57,5 @@ export const config: Sentry.BrowserOptions = { ...@@ -55,5 +57,5 @@ export const config: Sentry.BrowserOptions = {
}; };
export function configureScope(scope: Sentry.Scope) { export function configureScope(scope: Sentry.Scope) {
scope.setTag('app_instance', process.env.NEXT_PUBLIC_APP_INSTANCE); scope.setTag('app_instance', appConfig.features.sentry.instance);
} }
...@@ -9,5 +9,8 @@ fi ...@@ -9,5 +9,8 @@ fi
# Execute script for replace build-time ENVs placeholders with their values at runtime # Execute script for replace build-time ENVs placeholders with their values at runtime
./replace_envs.sh ./replace_envs.sh
echo "starting Nextjs" # Print list of enabled features
node ./feature-reporter.js
echo "Starting Next.js application"
exec "$@" exec "$@"
\ No newline at end of file
...@@ -64,11 +64,13 @@ async function checkPlaceholdersCongruity(runTimeEnvs: Record<string, string>) { ...@@ -64,11 +64,13 @@ async function checkPlaceholdersCongruity(runTimeEnvs: Record<string, string>) {
} }
if (inconsistencies.length > 0) { 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) => { 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(); throw new Error();
} }
......
/node_modules
/build
index.js
\ No newline at end of file
#!/bin/bash
rm -rf ./build
yarn compile_config
yarn build
dotenv -e ../../../configs/envs/.env.main -e ../../../configs/envs/.env.secrets yarn print_report
\ No newline at end of file
/* 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();
}
{
"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"
}
}
{
"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,
}
}
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),
},
};
This diff is collapsed.
...@@ -186,7 +186,6 @@ frontend: ...@@ -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_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS: '' 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_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_NETWORK_RPC_URL: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET: coinbase NEXT_PUBLIC_WEB3_DEFAULT_WALLET: coinbase
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: true NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET: true
...@@ -199,6 +198,5 @@ frontend: ...@@ -199,6 +198,5 @@ frontend:
NEXT_PUBLIC_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw NEXT_PUBLIC_L2_WITHDRAWAL_URL: https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
envFromSecret: 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_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 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
...@@ -144,7 +144,6 @@ frontend: ...@@ -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_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_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_NETWORK_VERIFICATION_TYPE: validation
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: https://airtable.com/shrqUAcjgGJ4jU88C NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: https://airtable.com/shrqUAcjgGJ4jU88C
NEXT_PUBLIC_APP_ENV: stable NEXT_PUBLIC_APP_ENV: stable
...@@ -160,7 +159,6 @@ frontend: ...@@ -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_MARKETPLACE_CONFIG_URL: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
envFromSecret: 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 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 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 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: ...@@ -107,8 +107,6 @@ frontend:
_default: '' _default: ''
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND: 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%)" _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: NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://goerli.optimism.io _default: https://goerli.optimism.io
NEXT_PUBLIC_WEB3_DEFAULT_WALLET: NEXT_PUBLIC_WEB3_DEFAULT_WALLET:
...@@ -133,8 +131,6 @@ frontend: ...@@ -133,8 +131,6 @@ frontend:
_default: https://app.optimism.io/bridge/withdraw _default: https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: NEXT_PUBLIC_GRAPHIQL_TRANSACTION:
_default: 0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62 _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: 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 _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: SENTRY_CSP_REPORT_URI:
......
...@@ -111,8 +111,6 @@ frontend: ...@@ -111,8 +111,6 @@ frontend:
_default: true _default: true
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: NEXT_PUBLIC_GRAPHIQL_TRANSACTION:
_default: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d _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: 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 _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: SENTRY_CSP_REPORT_URI:
......
...@@ -59,7 +59,7 @@ For all types of dependencies: ...@@ -59,7 +59,7 @@ For all types of dependencies:
These are the steps that you have to follow to make everything work: 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 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 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 4. Add the variable to CI configs where it is needed
- `deploy/values/review/values.yaml.gotmpl` - review development environment - `deploy/values/review/values.yaml.gotmpl` - review development environment
......
This diff is collapsed.
import { compile } from 'path-to-regexp'; import { compile } from 'path-to-regexp';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import isNeedProxy from './isNeedProxy'; import isNeedProxy from './isNeedProxy';
import { RESOURCES } from './resources'; import { RESOURCES } from './resources';
...@@ -12,8 +12,8 @@ export default function buildUrl<R extends ResourceName>( ...@@ -12,8 +12,8 @@ export default function buildUrl<R extends ResourceName>(
queryParams?: Record<string, string | Array<string> | number | null | undefined>, queryParams?: Record<string, string | Array<string> | number | null | undefined>,
): string { ): string {
const resource: ApiResource = RESOURCES[resourceName]; const resource: ApiResource = RESOURCES[resourceName];
const baseUrl = isNeedProxy() ? appConfig.app.baseUrl : (resource.endpoint || appConfig.api.endpoint); const baseUrl = isNeedProxy() ? config.app.baseUrl : (resource.endpoint || config.api.endpoint);
const basePath = resource.basePath !== undefined ? resource.basePath : appConfig.api.basePath; const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath;
const path = isNeedProxy() ? '/node-api/proxy' + basePath + resource.path : basePath + resource.path; const path = isNeedProxy() ? '/node-api/proxy' + basePath + resource.path : basePath + resource.path;
const url = new URL(compile(path)(pathParams), baseUrl); const url = new URL(compile(path)(pathParams), baseUrl);
......
import { compile } from 'path-to-regexp'; import { compile } from 'path-to-regexp';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { RESOURCES } from './resources'; import { RESOURCES } from './resources';
import type { ApiResource, ResourceName } from './resources'; import type { ApiResource, ResourceName } from './resources';
...@@ -11,8 +11,8 @@ export default function buildUrlNode( ...@@ -11,8 +11,8 @@ export default function buildUrlNode(
queryParams?: Record<string, string | number | undefined>, queryParams?: Record<string, string | number | undefined>,
) { ) {
const resource: ApiResource = typeof _resource === 'string' ? RESOURCES[_resource] : _resource; const resource: ApiResource = typeof _resource === 'string' ? RESOURCES[_resource] : _resource;
const baseUrl = resource.endpoint || appConfig.api.endpoint; const baseUrl = resource.endpoint || config.api.endpoint;
const basePath = resource.basePath !== undefined ? resource.basePath : appConfig.api.basePath; const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath;
const path = basePath + resource.path; const path = basePath + resource.path;
const url = new URL(compile(path)(pathParams), baseUrl); const url = new URL(compile(path)(pathParams), baseUrl);
......
import appConfig from 'configs/app/config'; import config from 'configs/app';
// FIXME // FIXME
// I was not able to figure out how to send CORS with credentials from localhost // I was not able to figure out how to send CORS with credentials from localhost
// unsuccessfully tried different ways, even custom local dev domain // unsuccessfully tried different ways, even custom local dev domain
// so for local development we have to use next.js api as proxy server // so for local development we have to use next.js api as proxy server
export default function isNeedProxy() { export default function isNeedProxy() {
if (appConfig.app.useNextJsProxy) { if (config.app.useProxy) {
return true; return true;
} }
return appConfig.app.host === 'localhost' && appConfig.app.host !== appConfig.api.host; return config.app.host === 'localhost' && config.app.host !== config.api.host;
} }
...@@ -59,7 +59,7 @@ import type { VisualizedContract } from 'types/api/visualization'; ...@@ -59,7 +59,7 @@ import type { VisualizedContract } from 'types/api/visualization';
import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals'; import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals';
import type { ArrayElement } from 'types/utils'; import type { ArrayElement } from 'types/utils';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export interface ApiResource { export interface ApiResource {
path: ResourcePath; path: ResourcePath;
...@@ -111,58 +111,58 @@ export const RESOURCES = { ...@@ -111,58 +111,58 @@ export const RESOURCES = {
address_verification: { address_verification: {
path: '/api/v1/chains/:chainId/verified-addresses:type', path: '/api/v1/chains/:chainId/verified-addresses:type',
pathParams: [ 'chainId' as const, 'type' as const ], pathParams: [ 'chainId' as const, 'type' as const ],
endpoint: appConfig.contractInfoApi.endpoint, endpoint: config.features.verifiedTokens.api.endpoint,
basePath: appConfig.contractInfoApi.basePath, basePath: config.features.verifiedTokens.api.basePath,
needAuth: true, needAuth: true,
}, },
verified_addresses: { verified_addresses: {
path: '/api/v1/chains/:chainId/verified-addresses', path: '/api/v1/chains/:chainId/verified-addresses',
pathParams: [ 'chainId' as const ], pathParams: [ 'chainId' as const ],
endpoint: appConfig.contractInfoApi.endpoint, endpoint: config.features.verifiedTokens.api.endpoint,
basePath: appConfig.contractInfoApi.basePath, basePath: config.features.verifiedTokens.api.basePath,
needAuth: true, needAuth: true,
}, },
token_info_applications_config: { token_info_applications_config: {
path: '/api/v1/chains/:chainId/token-info-submissions/selectors', path: '/api/v1/chains/:chainId/token-info-submissions/selectors',
pathParams: [ 'chainId' as const ], pathParams: [ 'chainId' as const ],
endpoint: appConfig.adminServiceApi.endpoint, endpoint: config.features.addressVerification.api.endpoint,
basePath: appConfig.adminServiceApi.basePath, basePath: config.features.addressVerification.api.basePath,
needAuth: true, needAuth: true,
}, },
token_info_applications: { token_info_applications: {
path: '/api/v1/chains/:chainId/token-info-submissions/:id?', path: '/api/v1/chains/:chainId/token-info-submissions/:id?',
pathParams: [ 'chainId' as const, 'id' as const ], pathParams: [ 'chainId' as const, 'id' as const ],
endpoint: appConfig.adminServiceApi.endpoint, endpoint: config.features.addressVerification.api.endpoint,
basePath: appConfig.adminServiceApi.basePath, basePath: config.features.addressVerification.api.basePath,
needAuth: true, needAuth: true,
}, },
// STATS // STATS
stats_counters: { stats_counters: {
path: '/api/v1/counters', path: '/api/v1/counters',
endpoint: appConfig.statsApi.endpoint, endpoint: config.features.stats.api.endpoint,
basePath: appConfig.statsApi.basePath, basePath: config.features.stats.api.basePath,
}, },
stats_lines: { stats_lines: {
path: '/api/v1/lines', path: '/api/v1/lines',
endpoint: appConfig.statsApi.endpoint, endpoint: config.features.stats.api.endpoint,
basePath: appConfig.statsApi.basePath, basePath: config.features.stats.api.basePath,
}, },
stats_line: { stats_line: {
path: '/api/v1/lines/:id', path: '/api/v1/lines/:id',
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
endpoint: appConfig.statsApi.endpoint, endpoint: config.features.stats.api.endpoint,
basePath: appConfig.statsApi.basePath, basePath: config.features.stats.api.basePath,
}, },
// VISUALIZATION // VISUALIZATION
visualize_sol2uml: { visualize_sol2uml: {
path: '/api/v1/solidity\\:visualize-contracts', path: '/api/v1/solidity\\:visualize-contracts',
endpoint: appConfig.visualizeApi.endpoint, endpoint: config.features.sol2uml.api.endpoint,
basePath: appConfig.visualizeApi.basePath, basePath: config.features.sol2uml.api.basePath,
}, },
// BLOCKS, TXS // BLOCKS, TXS
...@@ -345,8 +345,8 @@ export const RESOURCES = { ...@@ -345,8 +345,8 @@ export const RESOURCES = {
token_verified_info: { token_verified_info: {
path: '/api/v1/chains/:chainId/token-infos/:hash', path: '/api/v1/chains/:chainId/token-infos/:hash',
pathParams: [ 'chainId' as const, 'hash' as const ], pathParams: [ 'chainId' as const, 'hash' as const ],
endpoint: appConfig.contractInfoApi.endpoint, endpoint: config.features.verifiedTokens.api.endpoint,
basePath: appConfig.contractInfoApi.basePath, basePath: config.features.verifiedTokens.api.basePath,
}, },
token_counters: { token_counters: {
path: '/api/v2/tokens/:hash/counters', path: '/api/v2/tokens/:hash/counters',
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { CsrfData } from 'types/client/account'; 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 isBodyAllowed from 'lib/api/isBodyAllowed';
import isNeedProxy from 'lib/api/isNeedProxy'; import isNeedProxy from 'lib/api/isNeedProxy';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
...@@ -49,7 +49,7 @@ export default function useApiFetch() { ...@@ -49,7 +49,7 @@ export default function useApiFetch() {
// for user authentication in My account // 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) // 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 // change condition here if something is changed
credentials: appConfig.account.isEnabled ? 'include' : 'same-origin', credentials: config.features.account.isEnabled ? 'include' : 'same-origin',
headers, headers,
...fetchParams, ...fetchParams,
}, },
......
import type CspDev from 'csp-dev'; import type CspDev from 'csp-dev';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { KEY_WORDS } from '../utils'; import { KEY_WORDS } from '../utils';
const MAIN_DOMAINS = [ const MAIN_DOMAINS = [
`*.${ appConfig.app.host }`, `*.${ config.app.host }`,
appConfig.app.host, config.app.host,
appConfig.visualizeApi.endpoint, config.features.sol2uml.api.endpoint,
].filter(Boolean); ].filter(Boolean);
// eslint-disable-next-line no-restricted-properties // eslint-disable-next-line no-restricted-properties
const REPORT_URI = process.env.SENTRY_CSP_REPORT_URI;
export function app(): CspDev.DirectiveDescriptor { export function app(): CspDev.DirectiveDescriptor {
return { return {
...@@ -26,18 +25,18 @@ export function app(): CspDev.DirectiveDescriptor { ...@@ -26,18 +25,18 @@ export function app(): CspDev.DirectiveDescriptor {
...MAIN_DOMAINS, ...MAIN_DOMAINS,
// webpack hmr in safari doesn't recognize localhost as 'self' for some reason // 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 // APIs
appConfig.api.endpoint, config.api.endpoint,
appConfig.api.socket, config.api.socket,
appConfig.statsApi.endpoint, config.features.stats.api.endpoint,
appConfig.visualizeApi.endpoint, config.features.sol2uml.api.endpoint,
appConfig.contractInfoApi.endpoint, config.features.verifiedTokens.api.endpoint,
appConfig.adminServiceApi.endpoint, config.features.addressVerification.api.endpoint,
// chain RPC server // chain RPC server
appConfig.network.rpcUrl, config.chain.rpcUrl,
'https://infragrid.v.network', // RPC providers 'https://infragrid.v.network', // RPC providers
// github (spec for api-docs page) // github (spec for api-docs page)
...@@ -50,7 +49,7 @@ export function app(): CspDev.DirectiveDescriptor { ...@@ -50,7 +49,7 @@ export function app(): CspDev.DirectiveDescriptor {
// next.js generates and rebuilds source maps in dev using eval() // next.js generates and rebuilds source maps in dev using eval()
// https://github.com/vercel/next.js/issues/14221#issuecomment-657258278 // 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 // hash of ColorModeScript
'\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'', '\'sha256-e7MRMmTzLsLQvIy1iizO1lXf7VWYoQ6ysj5fuUzvRwE=\'',
...@@ -109,9 +108,9 @@ export function app(): CspDev.DirectiveDescriptor { ...@@ -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': [
REPORT_URI, config.features.sentry.cspReportUrl,
], ],
} : {}), } : {}),
}; };
......
import type CspDev from 'csp-dev'; import type CspDev from 'csp-dev';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export function googleAnalytics(): CspDev.DirectiveDescriptor { export function googleAnalytics(): CspDev.DirectiveDescriptor {
if (!appConfig.googleAnalytics.propertyId) { if (!config.features.googleAnalytics.isEnabled) {
return {}; return {};
} }
......
import type CspDev from 'csp-dev'; import type CspDev from 'csp-dev';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export function googleReCaptcha(): CspDev.DirectiveDescriptor { export function googleReCaptcha(): CspDev.DirectiveDescriptor {
if (!appConfig.reCaptcha.siteKey) { if (!config.services.reCaptcha.siteKey) {
return {}; return {};
} }
......
import type CspDev from 'csp-dev'; import type CspDev from 'csp-dev';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export function mixpanel(): CspDev.DirectiveDescriptor { export function mixpanel(): CspDev.DirectiveDescriptor {
if (!appConfig.mixpanel.projectToken) { if (!config.features.mixpanel.isEnabled) {
return {}; return {};
} }
......
import type CspDev from 'csp-dev'; import type CspDev from 'csp-dev';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export function walletConnect(): CspDev.DirectiveDescriptor { export function walletConnect(): CspDev.DirectiveDescriptor {
if (!appConfig.walletConnect.projectId || !appConfig.network.rpcUrl) { if (!config.features.blockchainInteraction.isEnabled) {
return {}; return {};
} }
......
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { useAppContext } from 'lib/contexts/app'; import { useAppContext } from 'lib/contexts/app';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
export default function useHasAccount() { export default function useHasAccount() {
const appProps = useAppContext(); const appProps = useAppContext();
if (!appConfig.account.isEnabled) { if (!config.features.account.isEnabled) {
return false; return false;
} }
......
import React from 'react'; import React from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import isBrowser from 'lib/isBrowser'; import isBrowser from 'lib/isBrowser';
const base = 'https://github.com/blockscout/blockscout/issues/new/'; const base = 'https://github.com/blockscout/blockscout/issues/new/';
const labels = 'new UI'; 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) { export default function useIssueUrl(backendVersion: string | undefined) {
const [ userAgent, setUserAgent ] = React.useState(''); const [ userAgent, setUserAgent ] = React.useState('');
...@@ -24,7 +24,7 @@ export default function useIssueUrl(backendVersion: string | undefined) { ...@@ -24,7 +24,7 @@ export default function useIssueUrl(backendVersion: string | undefined) {
### Environment ### Environment
* Backend Version/branch/commit: ${ backendVersion } * 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 } * User Agent: ${ userAgent }
### Steps to reproduce ### Steps to reproduce
......
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export default function useLoginUrl() { export default function useLoginUrl() {
const router = useRouter(); 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 } });
} }
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items'; 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 abiIcon from 'icons/ABI.svg';
import apiKeysIcon from 'icons/API.svg'; import apiKeysIcon from 'icons/API.svg';
import appsIcon from 'icons/apps.svg'; import appsIcon from 'icons/apps.svg';
...@@ -43,9 +43,6 @@ export function isInternalItem(item: NavItem): item is NavItemInternal { ...@@ -43,9 +43,6 @@ export function isInternalItem(item: NavItem): item is NavItemInternal {
} }
export default function useNavItems(): ReturnType { export default function useNavItems(): ReturnType {
const isMarketplaceAvailable = Boolean(appConfig.marketplace.configUrl && appConfig.network.rpcUrl);
const hasAPIDocs = appConfig.apiDoc.specUrl;
const router = useRouter(); const router = useRouter();
const pathname = router.pathname; const pathname = router.pathname;
...@@ -74,7 +71,7 @@ export default function useNavItems(): ReturnType { ...@@ -74,7 +71,7 @@ export default function useNavItems(): ReturnType {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
{ text: 'Verified contracts', nextRoute: { pathname: '/verified-contracts' as const }, icon: verifiedIcon, isActive: pathname === '/verified-contracts' }; { 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 = [ blockchainNavItems = [
[ [
txs, txs,
...@@ -101,7 +98,7 @@ export default function useNavItems(): ReturnType { ...@@ -101,7 +98,7 @@ export default function useNavItems(): ReturnType {
blocks, blocks,
topAccounts, topAccounts,
verifiedContracts, verifiedContracts,
appConfig.beaconChain.hasBeaconChain && { config.features.beaconChain.isEnabled && {
text: 'Withdrawals', text: 'Withdrawals',
nextRoute: { pathname: '/withdrawals' as const }, nextRoute: { pathname: '/withdrawals' as const },
icon: withdrawalsIcon, icon: withdrawalsIcon,
...@@ -111,18 +108,18 @@ export default function useNavItems(): ReturnType { ...@@ -111,18 +108,18 @@ export default function useNavItems(): ReturnType {
} }
const apiNavItems: Array<NavItem> = [ const apiNavItems: Array<NavItem> = [
hasAPIDocs ? { config.features.restApiDocs.isEnabled ? {
text: 'REST API', text: 'REST API',
nextRoute: { pathname: '/api-docs' as const }, nextRoute: { pathname: '/api-docs' as const },
icon: apiDocsIcon, icon: apiDocsIcon,
isActive: pathname === '/api-docs', isActive: pathname === '/api-docs',
} : null, } : null,
{ config.features.graphqlApiDocs.isEnabled ? {
text: 'GraphQL', text: 'GraphQL',
nextRoute: { pathname: '/graphiql' as const }, nextRoute: { pathname: '/graphiql' as const },
icon: graphQLIcon, icon: graphQLIcon,
isActive: pathname === '/graphiql', isActive: pathname === '/graphiql',
}, } : null,
{ {
text: 'RPC API', text: 'RPC API',
icon: rpcIcon, icon: rpcIcon,
...@@ -148,13 +145,13 @@ export default function useNavItems(): ReturnType { ...@@ -148,13 +145,13 @@ export default function useNavItems(): ReturnType {
icon: tokensIcon, icon: tokensIcon,
isActive: pathname.startsWith('/token'), isActive: pathname.startsWith('/token'),
}, },
isMarketplaceAvailable ? { config.features.marketplace.isEnabled ? {
text: 'Apps', text: 'Apps',
nextRoute: { pathname: '/apps' as const }, nextRoute: { pathname: '/apps' as const },
icon: appsIcon, icon: appsIcon,
isActive: pathname.startsWith('/app'), isActive: pathname.startsWith('/app'),
} : null, } : null,
appConfig.statsApi.endpoint ? { config.features.stats.isEnabled ? {
text: 'Charts & stats', text: 'Charts & stats',
nextRoute: { pathname: '/stats' as const }, nextRoute: { pathname: '/stats' as const },
icon: statsIcon, icon: statsIcon,
...@@ -166,10 +163,10 @@ export default function useNavItems(): ReturnType { ...@@ -166,10 +163,10 @@ export default function useNavItems(): ReturnType {
isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive), isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive),
subItems: apiNavItems, subItems: apiNavItems,
}, },
appConfig.navigation.otherLinks.length > 0 ? { config.UI.sidebar.otherLinks.length > 0 ? {
text: 'Other', text: 'Other',
icon: gearIcon, icon: gearIcon,
subItems: appConfig.navigation.otherLinks, subItems: config.UI.sidebar.otherLinks,
} : null, } : null,
].filter(Boolean); ].filter(Boolean);
...@@ -202,7 +199,7 @@ export default function useNavItems(): ReturnType { ...@@ -202,7 +199,7 @@ export default function useNavItems(): ReturnType {
icon: abiIcon, icon: abiIcon,
isActive: pathname === '/account/custom-abi', isActive: pathname === '/account/custom-abi',
}, },
appConfig.contractInfoApi.endpoint && appConfig.adminServiceApi.endpoint && { config.features.addressVerification.isEnabled && {
text: 'Verified addrs', text: 'Verified addrs',
nextRoute: { pathname: '/account/verified-addresses' as const }, nextRoute: { pathname: '/account/verified-addresses' as const },
icon: verifiedIcon, icon: verifiedIcon,
...@@ -218,5 +215,5 @@ export default function useNavItems(): ReturnType { ...@@ -218,5 +215,5 @@ export default function useNavItems(): ReturnType {
}; };
return { mainNavItems, accountNavItems, profileItem }; return { mainNavItems, accountNavItems, profileItem };
}, [ hasAPIDocs, isMarketplaceAvailable, pathname ]); }, [ pathname ]);
} }
...@@ -2,7 +2,7 @@ import type { Route } from 'nextjs-routes'; ...@@ -2,7 +2,7 @@ import type { Route } from 'nextjs-routes';
import type { ApiData, Metadata } from './types'; import type { ApiData, Metadata } from './types';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import getNetworkTitle from 'lib/networks/getNetworkTitle'; import getNetworkTitle from 'lib/networks/getNetworkTitle';
import compileValue from './compileValue'; import compileValue from './compileValue';
...@@ -12,7 +12,7 @@ export default function generate<R extends Route>(route: R, apiData?: ApiData<R> ...@@ -12,7 +12,7 @@ export default function generate<R extends Route>(route: R, apiData?: ApiData<R>
const params = { const params = {
...route.query, ...route.query,
...apiData, ...apiData,
network_name: appConfig.network.name, network_name: config.chain.name,
network_title: getNetworkTitle(), network_title: getNetworkTitle(),
}; };
......
import appConfig from 'configs/app/config'; import config from 'configs/app';
import delay from 'lib/delay'; import delay from 'lib/delay';
export default function isGoogleAnalyticsLoaded(retries = 3): Promise<boolean> { export default function isGoogleAnalyticsLoaded(retries = 3): Promise<boolean> {
if (!retries || !appConfig.googleAnalytics.propertyId) { if (!retries || !config.features.googleAnalytics.isEnabled) {
return Promise.resolve(false); return Promise.resolve(false);
} }
return typeof window.ga?.getAll === 'function' ? Promise.resolve(true) : delay(500).then(() => isGoogleAnalyticsLoaded(retries - 1)); return typeof window.ga?.getAll === 'function' ? Promise.resolve(true) : delay(500).then(() => isGoogleAnalyticsLoaded(retries - 1));
......
import mixpanel from 'mixpanel-browser'; import mixpanel from 'mixpanel-browser';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import type { EventTypes, EventPayload } from './utils'; import type { EventTypes, EventPayload } from './utils';
...@@ -12,7 +12,7 @@ export default function logEvent<EventType extends EventTypes>( ...@@ -12,7 +12,7 @@ export default function logEvent<EventType extends EventTypes>(
optionsOrCallback?: TrackFnArgs[2], optionsOrCallback?: TrackFnArgs[2],
callback?: TrackFnArgs[3], callback?: TrackFnArgs[3],
) { ) {
if (!appConfig.mixpanel.projectToken) { if (!config.features.mixpanel.isEnabled) {
return; return;
} }
mixpanel.track(type, properties, optionsOrCallback, callback); mixpanel.track(type, properties, optionsOrCallback, callback);
......
...@@ -5,7 +5,7 @@ import { useRouter } from 'next/router'; ...@@ -5,7 +5,7 @@ import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import { deviceType } from 'react-device-detect'; import { deviceType } from 'react-device-detect';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
...@@ -19,21 +19,21 @@ export default function useMixpanelInit() { ...@@ -19,21 +19,21 @@ export default function useMixpanelInit() {
React.useEffect(() => { React.useEffect(() => {
isGoogleAnalyticsLoaded().then((isGALoaded) => { isGoogleAnalyticsLoaded().then((isGALoaded) => {
if (!appConfig.mixpanel.projectToken) { if (!config.features.mixpanel.isEnabled) {
return; return;
} }
const debugFlagCookie = cookies.get(cookies.NAMES.MIXPANEL_DEBUG); const debugFlagCookie = cookies.get(cookies.NAMES.MIXPANEL_DEBUG);
const config: Partial<Config> = { const mixpanelConfig: Partial<Config> = {
debug: Boolean(debugFlagQuery.current || debugFlagCookie), debug: Boolean(debugFlagQuery.current || debugFlagCookie),
}; };
const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN)); const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN));
mixpanel.init(appConfig.mixpanel.projectToken, config); mixpanel.init(config.features.mixpanel.projectToken, mixpanelConfig);
mixpanel.register({ mixpanel.register({
'Chain id': appConfig.network.id, 'Chain id': config.chain.id,
Environment: appConfig.isDev ? 'Dev' : 'Prod', Environment: config.app.isDev ? 'Dev' : 'Prod',
Authorized: isAuth, Authorized: isAuth,
'Viewport width': window.innerWidth, 'Viewport width': window.innerWidth,
'Viewport height': window.innerHeight, 'Viewport height': window.innerHeight,
......
...@@ -2,7 +2,7 @@ import { usePathname } from 'next/navigation'; ...@@ -2,7 +2,7 @@ import { usePathname } from 'next/navigation';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import getPageType from './getPageType'; import getPageType from './getPageType';
...@@ -18,7 +18,7 @@ export default function useLogPageView(isInited: boolean) { ...@@ -18,7 +18,7 @@ export default function useLogPageView(isInited: boolean) {
const page = getQueryParamString(router.query.page); const page = getQueryParamString(router.query.page);
React.useEffect(() => { React.useEffect(() => {
if (!appConfig.mixpanel.projectToken || !isInited) { if (!config.features.mixpanel.isEnabled || !isInited) {
return; return;
} }
......
import appConfig from 'configs/app/config'; import config from 'configs/app';
// TODO delete when page descriptions is refactored // TODO delete when page descriptions is refactored
export default function getNetworkTitle() { 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';
} }
import appConfig from 'configs/app/config'; import config from 'configs/app';
export default function getNetworkValidatorTitle() { export default function getNetworkValidatorTitle() {
return appConfig.network.verificationType === 'validation' ? 'validator' : 'miner'; return config.chain.verificationType === 'validation' ? 'validator' : 'miner';
} }
...@@ -3,7 +3,7 @@ import _mapValues from 'lodash/mapValues'; ...@@ -3,7 +3,7 @@ import _mapValues from 'lodash/mapValues';
import type { NetworkExplorer } from 'types/networks'; import type { NetworkExplorer } from 'types/networks';
import appConfig from 'configs/app/config'; import config from 'configs/app';
// for easy .env update // for easy .env update
// const NETWORK_EXPLORERS = JSON.stringify([ // const NETWORK_EXPLORERS = JSON.stringify([
...@@ -29,7 +29,7 @@ const stripTrailingSlash = (str: string) => str[str.length - 1] === '/' ? str.sl ...@@ -29,7 +29,7 @@ const stripTrailingSlash = (str: string) => str[str.length - 1] === '/' ? str.sl
const addLeadingSlash = (str: string) => str[0] === '/' ? str : '/' + str; const addLeadingSlash = (str: string) => str[0] === '/' ? str : '/' + str;
const networkExplorers: Array<NetworkExplorer> = (() => { const networkExplorers: Array<NetworkExplorer> = (() => {
return appConfig.network.explorers.map((explorer) => ({ return config.UI.explorers.items.map((explorer) => ({
...explorer, ...explorer,
baseUrl: stripTrailingSlash(explorer.baseUrl), baseUrl: stripTrailingSlash(explorer.baseUrl),
paths: _mapValues(explorer.paths, _compose(stripTrailingSlash, addLeadingSlash)), paths: _mapValues(explorer.paths, _compose(stripTrailingSlash, addLeadingSlash)),
......
import type { GetServerSideProps } from 'next'; import type { GetServerSideProps } from 'next';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export type Props = { export type Props = {
cookies: string; cookies: string;
...@@ -25,7 +25,7 @@ export const base: GetServerSideProps<Props> = async({ req, query }) => { ...@@ -25,7 +25,7 @@ export const base: GetServerSideProps<Props> = async({ req, query }) => {
}; };
export const account: GetServerSideProps<Props> = async(context) => { export const account: GetServerSideProps<Props> = async(context) => {
if (!appConfig.account.isEnabled) { if (!config.features.account.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -35,7 +35,7 @@ export const account: GetServerSideProps<Props> = async(context) => { ...@@ -35,7 +35,7 @@ export const account: GetServerSideProps<Props> = async(context) => {
}; };
export const verifiedAddresses: GetServerSideProps<Props> = async(context) => { export const verifiedAddresses: GetServerSideProps<Props> = async(context) => {
if (!appConfig.adminServiceApi.endpoint || !appConfig.contractInfoApi.endpoint) { if (!config.features.addressVerification.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -45,7 +45,7 @@ export const verifiedAddresses: GetServerSideProps<Props> = async(context) => { ...@@ -45,7 +45,7 @@ export const verifiedAddresses: GetServerSideProps<Props> = async(context) => {
}; };
export const beaconChain: GetServerSideProps<Props> = async(context) => { export const beaconChain: GetServerSideProps<Props> = async(context) => {
if (!appConfig.beaconChain.hasBeaconChain) { if (!config.features.beaconChain.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -55,7 +55,7 @@ export const beaconChain: GetServerSideProps<Props> = async(context) => { ...@@ -55,7 +55,7 @@ export const beaconChain: GetServerSideProps<Props> = async(context) => {
}; };
export const L2: GetServerSideProps<Props> = async(context) => { export const L2: GetServerSideProps<Props> = async(context) => {
if (!appConfig.L2.isL2Network) { if (!config.features.rollup.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -65,7 +65,7 @@ export const L2: GetServerSideProps<Props> = async(context) => { ...@@ -65,7 +65,7 @@ export const L2: GetServerSideProps<Props> = async(context) => {
}; };
export const marketplace: GetServerSideProps<Props> = async(context) => { export const marketplace: GetServerSideProps<Props> = async(context) => {
if (!appConfig.marketplace.configUrl || !appConfig.network.rpcUrl) { if (!config.features.marketplace.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -75,7 +75,7 @@ export const marketplace: GetServerSideProps<Props> = async(context) => { ...@@ -75,7 +75,7 @@ export const marketplace: GetServerSideProps<Props> = async(context) => {
}; };
export const apiDocs: GetServerSideProps<Props> = async(context) => { export const apiDocs: GetServerSideProps<Props> = async(context) => {
if (!appConfig.apiDoc.specUrl) { if (!config.features.restApiDocs.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -85,7 +85,7 @@ export const apiDocs: GetServerSideProps<Props> = async(context) => { ...@@ -85,7 +85,7 @@ export const apiDocs: GetServerSideProps<Props> = async(context) => {
}; };
export const csvExport: GetServerSideProps<Props> = async(context) => { export const csvExport: GetServerSideProps<Props> = async(context) => {
if (!appConfig.reCaptcha.siteKey) { if (!config.features.csvExport.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
...@@ -95,7 +95,7 @@ export const csvExport: GetServerSideProps<Props> = async(context) => { ...@@ -95,7 +95,7 @@ export const csvExport: GetServerSideProps<Props> = async(context) => {
}; };
export const stats: GetServerSideProps<Props> = async(context) => { export const stats: GetServerSideProps<Props> = async(context) => {
if (!appConfig.statsApi.endpoint) { if (!config.features.stats.isEnabled) {
return { return {
notFound: true, notFound: true,
}; };
......
...@@ -2,13 +2,13 @@ import type { NextRequest } from 'next/server'; ...@@ -2,13 +2,13 @@ import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { httpLogger } from 'lib/api/logger'; import { httpLogger } from 'lib/api/logger';
import { DAY } from 'lib/consts'; import { DAY } from 'lib/consts';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
export function account(req: NextRequest) { export function account(req: NextRequest) {
if (!appConfig.account.isEnabled) { if (!config.features.account.isEnabled) {
return; return;
} }
...@@ -24,7 +24,7 @@ export function account(req: NextRequest) { ...@@ -24,7 +24,7 @@ export function account(req: NextRequest) {
const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile'); const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile');
if ((isAccountRoute || isProfileRoute)) { 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); return NextResponse.redirect(authUrl);
} }
} }
...@@ -35,7 +35,7 @@ export function account(req: NextRequest) { ...@@ -35,7 +35,7 @@ export function account(req: NextRequest) {
if (apiTokenCookie) { if (apiTokenCookie) {
// temporary solution // temporary solution
// TODO check app for integrity https://github.com/blockscout/frontend/issues/1028 and make typescript happy here // 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({ httpLogger.logger.error({
message: 'Logout URL is not configured', message: 'Logout URL is not configured',
}); });
...@@ -46,7 +46,7 @@ export function account(req: NextRequest) { ...@@ -46,7 +46,7 @@ export function account(req: NextRequest) {
// logout URL is always external URL in auth0.com sub-domain // logout URL is always external URL in auth0.com sub-domain
// at least we hope so // 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 res.cookies.delete(cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED); // reset cookie to show email verification page again
return res; return res;
...@@ -55,7 +55,7 @@ export function account(req: NextRequest) { ...@@ -55,7 +55,7 @@ export function account(req: NextRequest) {
// if user hasn't seen email verification page, make redirect to it // if user hasn't seen email verification page, make redirect to it
if (!req.cookies.get(cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED)) { if (!req.cookies.get(cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED)) {
if (!req.nextUrl.pathname.includes('/auth/unverified-email')) { 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); const res = NextResponse.redirect(url);
res.cookies.set({ res.cookies.set({
name: cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED, name: cookies.NAMES.CONFIRM_EMAIL_PAGE_VIEWED,
......
...@@ -3,13 +3,13 @@ import type { WindowProvider } from 'wagmi'; ...@@ -3,13 +3,13 @@ import type { WindowProvider } from 'wagmi';
import 'wagmi/window'; import 'wagmi/window';
import appConfig from 'configs/app/config'; import config from 'configs/app';
export default function useProvider() { export default function useProvider() {
const [ provider, setProvider ] = React.useState<WindowProvider>(); const [ provider, setProvider ] = React.useState<WindowProvider>();
React.useEffect(() => { React.useEffect(() => {
if (!('ethereum' in window && window.ethereum)) { if (!('ethereum' in window && window.ethereum) || !config.features.web3Wallet.isEnabled) {
return; return;
} }
...@@ -18,11 +18,11 @@ export default function useProvider() { ...@@ -18,11 +18,11 @@ export default function useProvider() {
const providers = Array.isArray(window.ethereum.providers) ? window.ethereum.providers : [ window.ethereum ]; const providers = Array.isArray(window.ethereum.providers) ? window.ethereum.providers : [ window.ethereum ];
providers.forEach(async(provider) => { providers.forEach(async(provider) => {
if (appConfig.web3.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) { if (config.features.web3Wallet.defaultWallet === 'coinbase' && provider.isCoinbaseWallet) {
return setProvider(provider); return setProvider(provider);
} }
if (appConfig.web3.defaultWallet === 'metamask' && provider.isMetaMask) { if (config.features.web3Wallet.defaultWallet === 'metamask' && provider.isMetaMask) {
return setProvider(provider); return setProvider(provider);
} }
}); });
......
...@@ -3,7 +3,7 @@ import type { WalletType, WalletInfo } from 'types/client/wallets'; ...@@ -3,7 +3,7 @@ import type { WalletType, WalletInfo } from 'types/client/wallets';
import coinbaseIcon from 'icons/wallets/coinbase.svg'; import coinbaseIcon from 'icons/wallets/coinbase.svg';
import metamaskIcon from 'icons/wallets/metamask.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: { metamask: {
name: 'MetaMask', name: 'MetaMask',
icon: metamaskIcon, icon: metamaskIcon,
......
...@@ -5,7 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; ...@@ -5,7 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import type { AppProps } from 'next/app'; import type { AppProps } from 'next/app';
import React, { useState } from 'react'; import React, { useState } from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { AppContextProvider } from 'lib/contexts/app'; import { AppContextProvider } from 'lib/contexts/app';
import { ChakraProvider } from 'lib/contexts/chakra'; import { ChakraProvider } from 'lib/contexts/chakra';
import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection'; import { ScrollDirectionProvider } from 'lib/contexts/scrollDirection';
...@@ -85,7 +85,7 @@ function MyApp({ Component, pageProps }: AppProps) { ...@@ -85,7 +85,7 @@ function MyApp({ Component, pageProps }: AppProps) {
<AppContextProvider pageProps={ pageProps }> <AppContextProvider pageProps={ pageProps }>
<QueryClientProvider client={ queryClient }> <QueryClientProvider client={ queryClient }>
<ScrollDirectionProvider> <ScrollDirectionProvider>
<SocketProvider url={ `${ appConfig.api.socket }${ appConfig.api.basePath }/socket/v2` }> <SocketProvider url={ `${ config.api.socket }${ config.api.basePath }/socket/v2` }>
<Component { ...pageProps }/> <Component { ...pageProps }/>
</SocketProvider> </SocketProvider>
</ScrollDirectionProvider> </ScrollDirectionProvider>
......
...@@ -3,7 +3,7 @@ import type { DocumentContext } from 'next/document'; ...@@ -3,7 +3,7 @@ import type { DocumentContext } from 'next/document';
import Document, { Html, Head, Main, NextScript } from 'next/document'; import Document, { Html, Head, Main, NextScript } from 'next/document';
import React from 'react'; import React from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import * as serverTiming from 'lib/next/serverTiming'; import * as serverTiming from 'lib/next/serverTiming';
import theme from 'theme'; import theme from 'theme';
...@@ -47,11 +47,11 @@ class MyDocument extends Document { ...@@ -47,11 +47,11 @@ class MyDocument extends Document {
// eslint-disable-next-line max-len // 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." 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:site_name" content="Blockscout"/>
<meta property="og:type" content="website"/> <meta property="og:type" content="website"/>
<meta name="twitter:card" content="summary_large_image"/> <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> </Head>
<body> <body>
<ColorModeScript initialColorMode={ theme.config.initialColorMode }/> <ColorModeScript initialColorMode={ theme.config.initialColorMode }/>
......
...@@ -2,7 +2,7 @@ import _pick from 'lodash/pick'; ...@@ -2,7 +2,7 @@ import _pick from 'lodash/pick';
import _pickBy from 'lodash/pickBy'; import _pickBy from 'lodash/pickBy';
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import fetchFactory from 'lib/api/nodeFetch'; import fetchFactory from 'lib/api/nodeFetch';
const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => { const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => {
...@@ -13,7 +13,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => { ...@@ -13,7 +13,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => {
const url = new URL( const url = new URL(
nextReq.url.replace(/^\/node-api\/proxy/, ''), 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)( const apiRes = await fetchFactory(nextReq)(
url.toString(), url.toString(),
......
export type WalletType = 'metamask' | 'coinbase'; export type WalletType = 'metamask' | 'coinbase' | 'none';
export interface WalletInfo { export interface WalletInfo {
name: string; name: string;
......
...@@ -7,7 +7,6 @@ export type NextPublicEnvs = { ...@@ -7,7 +7,6 @@ export type NextPublicEnvs = {
NEXT_PUBLIC_NETWORK_CURRENCY_NAME?: string; NEXT_PUBLIC_NETWORK_CURRENCY_NAME?: string;
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL?: string; NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL?: string;
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS?: string; NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS?: string;
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS?: string;
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME?: string; NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME?: string;
NEXT_PUBLIC_NETWORK_LOGO?: string; NEXT_PUBLIC_NETWORK_LOGO?: string;
NEXT_PUBLIC_NETWORK_LOGO_DARK?: string; NEXT_PUBLIC_NETWORK_LOGO_DARK?: string;
...@@ -34,18 +33,13 @@ export type NextPublicEnvs = { ...@@ -34,18 +33,13 @@ export type NextPublicEnvs = {
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER?: 'true' | 'false'; NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER?: 'true' | 'false';
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME?: 'true' | 'false'; NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME?: 'true' | 'false';
// Ads config // Text 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';
NEXT_PUBLIC_AD_TEXT_PROVIDER?: 'coinzilla' | 'none'; NEXT_PUBLIC_AD_TEXT_PROVIDER?: 'coinzilla' | 'none';
// App config // App config
NEXT_PUBLIC_APP_INSTANCE?: string;
NEXT_PUBLIC_APP_PROTOCOL?: 'http' | 'https'; NEXT_PUBLIC_APP_PROTOCOL?: 'http' | 'https';
NEXT_PUBLIC_APP_HOST: string; NEXT_PUBLIC_APP_HOST: string;
NEXT_PUBLIC_APP_PORT?: string; NEXT_PUBLIC_APP_PORT?: string;
NEXT_PUBLIC_APP_ENV?: string;
// API config // API config
NEXT_PUBLIC_API_PROTOCOL?: 'http' | 'https'; NEXT_PUBLIC_API_PROTOCOL?: 'http' | 'https';
...@@ -56,11 +50,8 @@ export type NextPublicEnvs = { ...@@ -56,11 +50,8 @@ export type NextPublicEnvs = {
NEXT_PUBLIC_STATS_API_HOST?: string; NEXT_PUBLIC_STATS_API_HOST?: string;
NEXT_PUBLIC_VISUALIZE_API_HOST?: string; NEXT_PUBLIC_VISUALIZE_API_HOST?: string;
NEXT_PUBLIC_CONTRACT_INFO_API_HOST?: string; NEXT_PUBLIC_CONTRACT_INFO_API_HOST?: string;
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST?: string;
// external services config // external services config
NEXT_PUBLIC_SENTRY_DSN?: string;
SENTRY_CSP_REPORT_URI?: string;
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID?: string; NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID?: string;
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY?: string; NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY?: string;
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID?: string; NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID?: string;
...@@ -73,7 +64,9 @@ export type NextPublicEnvs = { ...@@ -73,7 +64,9 @@ export type NextPublicEnvs = {
& NextPublicEnvsAccount & NextPublicEnvsAccount
& NextPublicEnvsMarketplace & NextPublicEnvsMarketplace
& NextPublicEnvsRollup & NextPublicEnvsRollup
& NextPublicEnvsBeacon; & NextPublicEnvsBeacon
& NextPublicEnvsAdsBanner
& NextPublicEnvsSentry;
type NextPublicEnvsAccount = type NextPublicEnvsAccount =
{ {
...@@ -87,6 +80,7 @@ type NextPublicEnvsAccount = ...@@ -87,6 +80,7 @@ type NextPublicEnvsAccount =
NEXT_PUBLIC_AUTH_URL?: string; NEXT_PUBLIC_AUTH_URL?: string;
NEXT_PUBLIC_LOGOUT_URL: string; NEXT_PUBLIC_LOGOUT_URL: string;
NEXT_PUBLIC_AUTH0_CLIENT_ID: string; NEXT_PUBLIC_AUTH0_CLIENT_ID: string;
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST?: string;
} }
type NextPublicEnvsMarketplace = type NextPublicEnvsMarketplace =
...@@ -120,3 +114,30 @@ type NextPublicEnvsBeacon = ...@@ -120,3 +114,30 @@ type NextPublicEnvsBeacon =
NEXT_PUBLIC_HAS_BEACON_CHAIN?: undefined; NEXT_PUBLIC_HAS_BEACON_CHAIN?: undefined;
NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL?: 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;
}
...@@ -6,7 +6,7 @@ import React from 'react'; ...@@ -6,7 +6,7 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { AddressBlocksValidatedResponse } from 'types/api/address'; 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 { getResourceKey } from 'lib/api/useApiQuery';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
...@@ -94,7 +94,7 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => { ...@@ -94,7 +94,7 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => {
<Th width="17%">Age</Th> <Th width="17%">Age</Th>
<Th width="16%">Txn</Th> <Th width="16%">Txn</Th>
<Th width="25%">Gas used</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> </Tr>
</Thead> </Thead>
<Tbody> <Tbody>
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { CsvExportParams } from 'types/client/address'; 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 svgFileIcon from 'icons/files/csv.svg';
import useIsInitialLoading from 'lib/hooks/useIsInitialLoading'; import useIsInitialLoading from 'lib/hooks/useIsInitialLoading';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
...@@ -21,7 +21,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props) ...@@ -21,7 +21,7 @@ const AddressCsvExportLink = ({ className, address, params, isLoading }: Props)
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const isInitialLoading = useIsInitialLoading(isLoading); const isInitialLoading = useIsInitialLoading(isLoading);
if (!appConfig.reCaptcha.siteKey) { if (!config.features.csvExport.isEnabled) {
return null; return null;
} }
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { Block } from 'types/api/block'; 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 getBlockTotalReward from 'lib/block/getBlockTotalReward';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
...@@ -48,7 +48,7 @@ const AddressBlocksValidatedListItem = (props: Props) => { ...@@ -48,7 +48,7 @@ const AddressBlocksValidatedListItem = (props: Props) => {
/> />
</Flex> </Flex>
<Flex columnGap={ 2 } w="100%"> <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> <Skeleton isLoaded={ !props.isLoading } color="text_secondary">{ totalReward.toFixed() }</Skeleton>
</Flex> </Flex>
</ListItemMobile> </ListItemMobile>
......
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import React from 'react'; import React from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import ChartWidget from 'ui/shared/chart/ChartWidget'; import ChartWidget from 'ui/shared/chart/ChartWidget';
...@@ -16,7 +16,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => { ...@@ -16,7 +16,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => {
const items = React.useMemo(() => data?.map(({ date, value }) => ({ const items = React.useMemo(() => data?.map(({ date, value }) => ({
date: new Date(date), 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 ]); })), [ data ]);
return ( return (
...@@ -26,7 +26,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => { ...@@ -26,7 +26,7 @@ const AddressCoinBalanceChart = ({ addressHash }: Props) => {
items={ items } items={ items }
isLoading={ isLoading } isLoading={ isLoading }
h="300px" h="300px"
units={ appConfig.network.currency.symbol } units={ config.chain.currency.symbol }
/> />
); );
}; };
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { AddressCoinBalanceHistoryResponse } from 'types/api/address'; import type { AddressCoinBalanceHistoryResponse } from 'types/api/address';
import type { PaginationParams } from 'ui/shared/pagination/types'; 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 ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination'; import Pagination from 'ui/shared/pagination/Pagination';
...@@ -31,7 +31,7 @@ const AddressCoinBalanceHistory = ({ query }: Props) => { ...@@ -31,7 +31,7 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
<Th width="20%">Block</Th> <Th width="20%">Block</Th>
<Th width="20%">Txn</Th> <Th width="20%">Txn</Th>
<Th width="20%">Age</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> <Th width="20%" isNumeric>Delta</Th>
</Tr> </Tr>
</Thead> </Thead>
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { AddressCoinBalanceHistoryItem } from 'types/api/address'; 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 { WEI, ZERO } from 'lib/consts';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
...@@ -28,7 +28,7 @@ const AddressCoinBalanceListItem = (props: Props) => { ...@@ -28,7 +28,7 @@ const AddressCoinBalanceListItem = (props: Props) => {
<ListItemMobile rowGap={ 2 } isAnimated> <ListItemMobile rowGap={ 2 } isAnimated>
<Flex justifyContent="space-between" w="100%"> <Flex justifyContent="space-between" w="100%">
<Skeleton isLoaded={ !props.isLoading } fontWeight={ 600 }> <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>
<Skeleton isLoaded={ !props.isLoading }> <Skeleton isLoaded={ !props.isLoading }>
<Stat flexGrow="0"> <Stat flexGrow="0">
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { SmartContractMethodOutput } from 'types/api/contract'; import type { SmartContractMethodOutput } from 'types/api/contract';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import { WEI } from 'lib/consts'; import { WEI } from 'lib/consts';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
...@@ -39,7 +39,7 @@ const ContractMethodStatic = ({ data }: Props) => { ...@@ -39,7 +39,7 @@ const ContractMethodStatic = ({ data }: Props) => {
if (event.target.checked) { if (event.target.checked) {
setValue(BigNumber(initialValue).div(WEI).toFixed()); setValue(BigNumber(initialValue).div(WEI).toFixed());
setLabel(appConfig.network.currency.symbol || 'ETH'); setLabel(config.chain.currency.symbol || 'ETH');
} else { } else {
setValue(BigNumber(initialValue).toFixed()); setValue(BigNumber(initialValue).toFixed());
setLabel('WEI'); setLabel('WEI');
......
...@@ -5,7 +5,7 @@ import { Element } from 'react-scroll'; ...@@ -5,7 +5,7 @@ import { Element } from 'react-scroll';
import type { SmartContractMethod } from 'types/api/contract'; 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 iconLink from 'icons/link.svg';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
......
...@@ -3,7 +3,7 @@ import { useAccount, useWalletClient, useNetwork, useSwitchNetwork } from 'wagmi ...@@ -3,7 +3,7 @@ import { useAccount, useWalletClient, useNetwork, useSwitchNetwork } from 'wagmi
import type { SmartContractWriteMethod } from 'types/api/contract'; 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 useApiQuery from 'lib/api/useApiQuery';
import ContractMethodsAccordion from 'ui/address/contract/ContractMethodsAccordion'; import ContractMethodsAccordion from 'ui/address/contract/ContractMethodsAccordion';
import ContentLoader from 'ui/shared/ContentLoader'; import ContentLoader from 'ui/shared/ContentLoader';
...@@ -46,8 +46,8 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => { ...@@ -46,8 +46,8 @@ const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => {
throw new Error('Wallet is not connected'); throw new Error('Wallet is not connected');
} }
if (chain?.id && String(chain.id) !== config.network.id) { if (chain?.id && String(chain.id) !== config.chain.id) {
await switchNetworkAsync?.(Number(config.network.id)); await switchNetworkAsync?.(Number(config.chain.id));
} }
if (!contractAbi) { if (!contractAbi) {
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { Address } from 'types/api/address'; 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 { getResourceKey } from 'lib/api/useApiQuery';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
...@@ -65,15 +65,14 @@ const AddressBalance = ({ data, isLoading }: Props) => { ...@@ -65,15 +65,14 @@ const AddressBalance = ({ data, isLoading }: Props) => {
}); });
const tokenData = React.useMemo(() => ({ const tokenData = React.useMemo(() => ({
address: appConfig.network.currency.address || '', name: config.chain.currency.name || '',
name: appConfig.network.currency.name || '',
icon_url: '', icon_url: '',
}), [ ]); }), [ ]);
return ( return (
<DetailsInfoItem <DetailsInfoItem
title="Balance" 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" flexWrap="nowrap"
alignItems="flex-start" alignItems="flex-start"
isLoading={ isLoading } isLoading={ isLoading }
...@@ -88,8 +87,8 @@ const AddressBalance = ({ data, isLoading }: Props) => { ...@@ -88,8 +87,8 @@ const AddressBalance = ({ data, isLoading }: Props) => {
<CurrencyValue <CurrencyValue
value={ data.coin_balance || '0' } value={ data.coin_balance || '0' }
exchangeRate={ data.exchange_rate } exchangeRate={ data.exchange_rate }
decimals={ String(appConfig.network.currency.decimals) } decimals={ String(config.chain.currency.decimals) }
currency={ appConfig.network.currency.symbol } currency={ config.chain.currency.symbol }
accuracyUsd={ 2 } accuracyUsd={ 2 }
accuracy={ 8 } accuracy={ 8 }
flexWrap="wrap" flexWrap="wrap"
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; 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 eastArrowIcon from 'icons/arrows/east.svg';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
...@@ -79,9 +79,9 @@ const TxInternalsListItem = ({ ...@@ -79,9 +79,9 @@ const TxInternalsListItem = ({
) } ) }
</Box> </Box>
<HStack spacing={ 3 }> <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 }> <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> </Skeleton>
</HStack> </HStack>
</ListItemMobile> </ListItemMobile>
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; 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 { default as Thead } from 'ui/shared/TheadSticky';
import AddressIntTxsTableItem from './AddressIntTxsTableItem'; import AddressIntTxsTableItem from './AddressIntTxsTableItem';
...@@ -26,7 +26,7 @@ const AddressIntTxsTable = ({ data, currentAddress, isLoading }: Props) => { ...@@ -26,7 +26,7 @@ const AddressIntTxsTable = ({ data, currentAddress, isLoading }: Props) => {
<Th width="48px" px={ 0 }/> <Th width="48px" px={ 0 }/>
<Th width="20%">To</Th> <Th width="20%">To</Th>
<Th width="20%" isNumeric> <Th width="20%" isNumeric>
Value { appConfig.network.currency.symbol } Value { config.chain.currency.symbol }
</Th> </Th>
</Tr> </Tr>
</Thead> </Thead>
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; 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 rightArrowIcon from 'icons/arrows/east.svg';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address'; import Address from 'ui/shared/address/Address';
...@@ -105,7 +105,7 @@ const AddressIntTxsTableItem = ({ ...@@ -105,7 +105,7 @@ const AddressIntTxsTableItem = ({
</Td> </Td>
<Td isNumeric verticalAlign="middle"> <Td isNumeric verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block" minW={ 6 }> <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> </Skeleton>
</Td> </Td>
</Tr> </Tr>
......
...@@ -2,7 +2,7 @@ import { Flex } from '@chakra-ui/react'; ...@@ -2,7 +2,7 @@ import { Flex } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { ZERO } from 'lib/consts'; import { ZERO } from 'lib/consts';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
...@@ -34,7 +34,7 @@ const TokenBalances = () => { ...@@ -34,7 +34,7 @@ const TokenBalances = () => {
accuracy: 8, accuracy: 8,
accuracyUsd: 2, accuracyUsd: 2,
exchangeRate: addressData?.exchange_rate, exchangeRate: addressData?.exchange_rate,
decimals: String(appConfig.network.currency.decimals), decimals: String(config.chain.currency.decimals),
}); });
const tokensInfo = getTokensTotalInfo(tokenQuery.data); const tokensInfo = getTokensTotalInfo(tokenQuery.data);
...@@ -52,8 +52,8 @@ const TokenBalances = () => { ...@@ -52,8 +52,8 @@ const TokenBalances = () => {
isLoading={ addressQuery.isLoading || tokenQuery.isLoading } isLoading={ addressQuery.isLoading || tokenQuery.isLoading }
/> />
<TokenBalancesItem <TokenBalancesItem
name={ `${ appConfig.network.currency.symbol } Balance` } name={ `${ config.chain.currency.symbol } Balance` }
value={ (!nativeUsd.eq(ZERO) ? `$${ nativeUsd.toFormat(2) } USD | ` : '') + `${ nativeValue } ${ appConfig.network.currency.symbol }` } value={ (!nativeUsd.eq(ZERO) ? `$${ nativeUsd.toFormat(2) } USD | ` : '') + `${ nativeValue } ${ config.chain.currency.symbol }` }
isLoading={ addressQuery.isLoading || tokenQuery.isLoading } isLoading={ addressQuery.isLoading || tokenQuery.isLoading }
/> />
<TokenBalancesItem <TokenBalancesItem
......
...@@ -12,7 +12,7 @@ import type { ...@@ -12,7 +12,7 @@ import type {
RootFields, RootFields,
} from '../types'; } from '../types';
import appConfig from 'configs/app/config'; import config from 'configs/app';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import LinkInternal from 'ui/shared/LinkInternal'; import LinkInternal from 'ui/shared/LinkInternal';
...@@ -49,7 +49,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) = ...@@ -49,7 +49,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
}; };
const response = await apiFetch<'address_verification', AddressCheckResponseSuccess, AddressVerificationResponseError>('address_verification', { const response = await apiFetch<'address_verification', AddressCheckResponseSuccess, AddressVerificationResponseError>('address_verification', {
fetchParams: { method: 'POST', body }, fetchParams: { method: 'POST', body },
pathParams: { chainId: appConfig.network.id, type: ':prepare' }, pathParams: { chainId: config.chain.id, type: ':prepare' },
}); });
if (response.status !== 'SUCCESS') { if (response.status !== 'SUCCESS') {
......
...@@ -15,7 +15,7 @@ import type { ...@@ -15,7 +15,7 @@ import type {
} from '../types'; } from '../types';
import type { VerifiedAddress } from 'types/api/account'; 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 useApiFetch from 'lib/api/useApiFetch';
import shortenString from 'lib/shortenString'; import shortenString from 'lib/shortenString';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
...@@ -62,7 +62,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre ...@@ -62,7 +62,7 @@ const AddressVerificationStepSignature = ({ address, signingMessage, contractCre
const response = await apiFetch<'address_verification', AddressValidationResponseSuccess, AddressVerificationResponseError>('address_verification', { const response = await apiFetch<'address_verification', AddressValidationResponseSuccess, AddressVerificationResponseError>('address_verification', {
fetchParams: { method: 'POST', body }, fetchParams: { method: 'POST', body },
pathParams: { chainId: appConfig.network.id, type: ':verify' }, pathParams: { chainId: config.chain.id, type: ':verify' },
}); });
if (response.status !== 'SUCCESS') { if (response.status !== 'SUCCESS') {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment