Commit 2478ee25 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #2583 from blockscout/release/v1-38-0

Fixes for release v1.38.0
parents a6d05af5 279dd666
......@@ -87,8 +87,11 @@ download_and_save_asset() {
else
# Check if the value is a URL
if [[ "$url" == http* ]]; then
# Download the asset using curl
curl -s -o "$destination" "$url"
# Download the asset using curl with timeouts
if ! curl -f -s --connect-timeout 5 --max-time 15 -o "$destination" "$url"; then
echo " [-] $env_var: Failed to download from $url (timeout or connection error)"
return 1
fi
else
# Convert single-quoted JSON-like content to valid JSON
json_content=$(echo "${!env_var}" | sed "s/'/\"/g")
......
......@@ -32,14 +32,20 @@ if (process.env.NEXT_PUBLIC_OG_IMAGE_URL) {
console.log('⏳ Making request to OG image generator service...');
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30_000);
const response = await fetch('https://bigs.services.blockscout.com/generate/og', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
signal: controller.signal,
});
clearTimeout(timeoutId);
if (response.ok) {
console.log('⬇️ Downloading the image...');
const buffer = await response.arrayBuffer();
......
......@@ -141,40 +141,32 @@ function getEnvsPlaceholders(filePath: string): Promise<Array<string>> {
function printDeprecationWarning(envsMap: Record<string, string>) {
if (envsMap.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY && envsMap.NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY variable is now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
console.warn('❗ The NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY variable is now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY variable.');
}
if (
(envsMap.NEXT_PUBLIC_SENTRY_DSN || envsMap.SENTRY_CSP_REPORT_URI || envsMap.NEXT_PUBLIC_SENTRY_ENABLE_TRACING) &&
envsMap.NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN
) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len
console.warn('The Sentry monitoring is now deprecated and will be removed in the next release. Please migrate to the Rollbar error monitoring.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
console.warn('❗ The Sentry monitoring is now deprecated and will be removed in the next release. Please migrate to the Rollbar error monitoring.');
}
if (
envsMap.NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME ||
envsMap.NEXT_PUBLIC_ROLLUP_L1_BASE_URL
) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_ROLLUP_L1_BASE_URL and NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_ROLLUP_PARENT_CHAIN variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
console.warn('❗ The NEXT_PUBLIC_ROLLUP_L1_BASE_URL and NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_ROLLUP_PARENT_CHAIN variable.');
}
if (
envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR ||
envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND
) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR and NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
console.warn('❗ The NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR and NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG variable.');
}
if (
......@@ -182,10 +174,8 @@ function printDeprecationWarning(envsMap: Record<string, string>) {
envsMap.NEXT_PUBLIC_AUTH_URL ||
envsMap.NEXT_PUBLIC_LOGOUT_URL
) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH_URL and NEXT_PUBLIC_LOGOUT_URL variables are now deprecated and will be removed in the next release.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
console.warn('❗ The NEXT_PUBLIC_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH_URL and NEXT_PUBLIC_LOGOUT_URL variables are now deprecated and will be removed in the next release.');
}
}
......
......@@ -6,14 +6,26 @@ const stripTrailingSlash = (str) => str[str.length - 1] === '/' ? str.slice(0, -
const fetchResource = async(url, formatter) => {
console.log('🌀 [next-sitemap] Fetching resource:', url);
try {
const res = await fetch(url);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 15_000);
const res = await fetch(url, {
signal: controller.signal,
});
clearTimeout(timeoutId);
if (res.ok) {
const data = await res.json();
console.log('✅ [next-sitemap] Data fetched for resource:', url);
return formatter(data);
}
} catch (error) {
console.log('🚨 [next-sitemap] Error fetching resource:', url, error);
if (error.name === 'AbortError') {
console.log('🚨 [next-sitemap] Request timeout for resource:', url);
} else {
console.log('🚨 [next-sitemap] Error fetching resource:', url, error);
}
}
};
......
......@@ -283,7 +283,7 @@ Settings for meta tags, OG tags and SEO
#### Token views
| Variable | Type | Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED | `boolean` | Show the "Hide scam tokens" toggle in the site settings dropdown. This option controls the visibility of tokens with a poor reputation in the search results. | - | - | `'["value","tx_fee"]'` | v1.38.0+ |
| NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED | `boolean` | Show the "Hide scam tokens" toggle in the site settings dropdown. This option controls the visibility of tokens with a poor reputation in the search results. | - | `false` | `true` | v1.38.0+ |
&nbsp;
......
......@@ -82,7 +82,6 @@ export const token: Address = {
creation_transaction_hash: '0xc38cf7377bf72d6436f63c37b01b24d032101f20ec1849286dc703c712f10c98',
creator_address_hash: '0x34A9c688512ebdB575e82C50c9803F6ba2916E72',
exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: false,
has_token_transfers: true,
has_tokens: true,
......@@ -96,7 +95,6 @@ export const eoa: Address = {
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: true,
has_token_transfers: false,
has_tokens: true,
......@@ -120,7 +118,6 @@ export const contract: Address = {
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: true,
has_token_transfers: false,
has_tokens: false,
......@@ -146,7 +143,6 @@ export const validator: Address = {
creation_transaction_hash: null,
creator_address_hash: null,
exchange_rate: '0.00432018',
has_decompiled_code: false,
has_logs: false,
has_token_transfers: false,
has_tokens: false,
......
......@@ -46,7 +46,7 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => {
const isTrackingDisabled = process.env.DISABLE_TRACKING === 'true';
if (!isTrackingDisabled) {
if (!isTrackingDisabled && !config.app.isDev) {
// log pageview
const hostname = req.headers.host;
const timestamp = new Date().toISOString();
......
......@@ -22,7 +22,6 @@ export const ADDRESS_INFO: Address = {
creation_transaction_hash: null,
creator_address_hash: ADDRESS_HASH,
exchange_rate: null,
has_decompiled_code: false,
has_logs: true,
has_token_transfers: false,
has_tokens: false,
......
......@@ -20,7 +20,6 @@ export interface Address extends UserTags {
zilliqa?: AddressZilliqaParams;
// TODO: if we are happy with tabs-counters method, should we delete has_something fields?
has_beacon_chain_withdrawals?: boolean;
has_decompiled_code: boolean;
has_logs: boolean;
has_token_transfers: boolean;
has_tokens: boolean;
......
......@@ -172,8 +172,8 @@ export interface BlockEpoch {
carbon_offsetting_transfer: TokenTransfer | null;
community_transfer: TokenTransfer | null;
reserve_bolster_transfer: TokenTransfer | null;
};
aggregated_election_rewards: Record<EpochRewardsType, BlockEpochElectionReward | null>;
} | null;
aggregated_election_rewards: Record<EpochRewardsType, BlockEpochElectionReward | null> | null;
}
export interface BlockEpochElectionRewardDetails {
......
......@@ -15,10 +15,10 @@ export type Pool = {
quote_token_address: string;
quote_token_symbol: string;
quote_token_icon_url: string | null;
base_token_fully_diluted_valuation_usd: string;
base_token_market_cap_usd: string;
quote_token_fully_diluted_valuation_usd: string;
quote_token_market_cap_usd: string;
base_token_fully_diluted_valuation_usd: string | null;
base_token_market_cap_usd: string | null;
quote_token_fully_diluted_valuation_usd: string | null;
quote_token_market_cap_usd: string | null;
liquidity: string;
dex: {
id: string;
......
......@@ -10,7 +10,7 @@ interface Props {
}
const ContractDetailsAlertVerificationSource = ({ data }: Props) => {
if (data?.is_verified_via_eth_bytecode_db) {
if (data?.is_verified && data?.is_verified_via_eth_bytecode_db) {
return (
<Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap">
<span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified using </span>
......@@ -24,7 +24,7 @@ const ContractDetailsAlertVerificationSource = ({ data }: Props) => {
);
}
if (data?.is_verified_via_sourcify) {
if (data?.is_verified && data?.is_verified_via_sourcify) {
return (
<Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap">
<span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified via Sourcify. </span>
......
......@@ -77,7 +77,6 @@ export default function useAddressQuery({ hash, isEnabled = true }: Params): Add
creation_transaction_hash: null,
exchange_rate: null,
ens_domain_name: null,
has_decompiled_code: false,
has_logs: false,
has_token_transfers: false,
has_tokens: false,
......
......@@ -25,7 +25,7 @@ const BlockEpochRewards = ({ heightOrHash }: Props) => {
return <DataFetchAlert/>;
}
if (!query.data) {
if (!query.data || (!query.data.aggregated_election_rewards && !query.data.distribution)) {
return <span>No block epoch rewards data</span>;
}
......
......@@ -12,6 +12,10 @@ interface Props {
}
const BlockEpochElectionRewards = ({ data, isLoading }: Props) => {
if (!data.aggregated_election_rewards) {
return null;
}
return (
<Box mt={ 8 }>
<Heading as="h4" size="sm" mb={ 3 }>Election rewards</Heading>
......
......@@ -15,6 +15,10 @@ interface Props {
const BlockEpochRewardsDistribution = ({ data, isLoading }: Props) => {
const isMobile = useIsMobile();
if (!data.distribution) {
return null;
}
if (!data.distribution.community_transfer && !data.distribution.carbon_offsetting_transfer && !data.distribution.reserve_bolster_transfer) {
return null;
}
......
import type { BlockEpoch } from 'types/api/block';
import type { ExcludeNull } from 'types/utils';
export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rewards'], num: number) {
const postfix1 = num !== 1 ? 's' : '';
......@@ -26,7 +27,7 @@ export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rew
return `${ num } ${ text }`;
}
export function getRewardDetailsTableTitles(type: keyof BlockEpoch['aggregated_election_rewards']): [string, string] {
export function getRewardDetailsTableTitles(type: keyof ExcludeNull<BlockEpoch['aggregated_election_rewards']>): [string, string] {
switch (type) {
case 'delegated_payment':
return [ 'Beneficiary', 'Validator' ];
......@@ -39,6 +40,6 @@ export function getRewardDetailsTableTitles(type: keyof BlockEpoch['aggregated_e
}
}
export function formatRewardType(type: keyof BlockEpoch['aggregated_election_rewards']) {
export function formatRewardType(type: keyof ExcludeNull<BlockEpoch['aggregated_election_rewards']>) {
return type.replaceAll('_', '-');
}
......@@ -67,7 +67,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }>
${ Number(data.base_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }
{ data.base_token_fully_diluted_valuation_usd ?
`$${ Number(data.base_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton>
</DetailsInfoItem.Value>
......@@ -79,7 +82,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }>
${ Number(data.base_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }
{ data.base_token_market_cap_usd ?
`$${ Number(data.base_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton>
</DetailsInfoItem.Value>
......@@ -91,7 +97,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }>
${ Number(data.quote_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }
{ data.quote_token_fully_diluted_valuation_usd ?
`$${ Number(data.quote_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton>
</DetailsInfoItem.Value>
......@@ -103,7 +112,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }>
${ Number(data.quote_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }
{ data.quote_token_market_cap_usd ?
`$${ Number(data.quote_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton>
</DetailsInfoItem.Value>
......
......@@ -31,7 +31,7 @@ const init = () => {
projectId: feature.walletConnect.projectId,
features: {
analytics: false,
email: true,
email: false,
socials: [],
onramp: false,
swaps: false,
......
......@@ -12,7 +12,7 @@ interface Props extends FeaturedNetwork {
isMobile?: boolean;
}
const NetworkMenuLink = ({ title, icon, isActive, isMobile, url, invertIconInDarkMode }: Props) => {
const NetworkMenuLink = ({ title, icon, isActive: isActiveProp, isMobile, url, invertIconInDarkMode }: Props) => {
const colors = useColors();
const darkModeFilter = { filter: 'brightness(0) invert(1)' };
const style = useColorModeValue({}, invertIconInDarkMode ? darkModeFilter : {});
......@@ -27,6 +27,21 @@ const NetworkMenuLink = ({ title, icon, isActive, isMobile, url, invertIconInDar
/>
);
const isActive = (() => {
if (isActiveProp !== undefined) {
return isActiveProp;
}
try {
const itemOrigin = new URL(url).origin;
const currentOrigin = window.location.origin;
return itemOrigin === currentOrigin;
} catch (error) {
return false;
}
})();
return (
<Box as="li" listStyleType="none">
<Flex
......
......@@ -76,7 +76,9 @@ const TxsStats = () => {
>
{ txCount24h && (
<StatsWidget
label={ txsStatsQuery.data?.transactions_24h?.title || 'Transactions' }
label={ txsStatsQuery.data?.transactions_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.transactions_24h?.title) :
'Transactions' }
value={ Number(txCount24h).toLocaleString() }
period="24h"
isLoading={ isLoading }
......@@ -85,7 +87,9 @@ const TxsStats = () => {
) }
{ operationalTxns24h && (
<StatsWidget
label={ txsStatsQuery.data?.operational_transactions_24h?.title || 'Daily op txns' }
label={ txsStatsQuery.data?.operational_transactions_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.operational_transactions_24h?.title) :
'Daily op txns' }
value={ Number(operationalTxns24h).toLocaleString() }
period="24h"
isLoading={ isLoading }
......@@ -93,7 +97,9 @@ const TxsStats = () => {
) }
{ pendingTxns && (
<StatsWidget
label={ txsStatsQuery.data?.pending_transactions_30m?.title || 'Pending transactions' }
label={ txsStatsQuery.data?.pending_transactions_30m?.title ?
getLabelFromTitle(txsStatsQuery.data?.pending_transactions_30m?.title) :
'Pending transactions' }
value={ Number(pendingTxns).toLocaleString() }
period={ isStatsFeatureEnabled ? '30min' : '1h' }
isLoading={ isLoading }
......@@ -101,7 +107,9 @@ const TxsStats = () => {
) }
{ txFeeSum24h && (
<StatsWidget
label={ txsStatsQuery.data?.transactions_fee_24h?.title || 'Transactions fees' }
label={ txsStatsQuery.data?.transactions_fee_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.transactions_fee_24h?.title) :
'Transactions fees' }
value={ txFeeSum24h.toLocaleString(undefined, { maximumFractionDigits: 2 }) }
valuePostfix={ thinsp + config.chain.currency.symbol }
period="24h"
......@@ -111,7 +119,9 @@ const TxsStats = () => {
) }
{ txFeeAvg && (
<StatsWidget
label={ txsStatsQuery.data?.average_transactions_fee_24h?.title || 'Avg. transaction fee' }
label={ txsStatsQuery.data?.average_transactions_fee_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.average_transactions_fee_24h?.title) :
'Avg. transaction fee' }
value={ txFeeAvg.usd ? txFeeAvg.usd : txFeeAvg.valueStr }
valuePrefix={ txFeeAvg.usd ? '$' : undefined }
valuePostfix={ txFeeAvg.usd ? undefined : thinsp + config.chain.currency.symbol }
......@@ -124,4 +134,9 @@ const TxsStats = () => {
);
};
// remove period from title
function getLabelFromTitle(title: string) {
return title.replace(/\s*\([^)]*\)\s*$/, '');
}
export default React.memo(TxsStats);
......@@ -14,6 +14,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import TruncatedValue from 'ui/shared/TruncatedValue';
interface Props {
data: VerifiedContract;
......@@ -57,11 +58,13 @@ const VerifiedContractsListItem = ({ data, isLoading }: Props) => {
flexShrink={ 0 }
/>
</Flex>
<Flex columnGap={ 3 }>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Balance { currencyUnits.ether }</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>{ balance }</span>
</Skeleton>
<Flex columnGap={ 3 } w="100%">
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 } flexShrink="0">Balance { currencyUnits.ether }</Skeleton>
<TruncatedValue
value={ balance }
isLoading={ isLoading }
/>
</Flex>
<Flex columnGap={ 3 }>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Txs count</Skeleton>
......
......@@ -12,6 +12,7 @@ import ContractCertifiedLabel from 'ui/shared/ContractCertifiedLabel';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import TruncatedValue from 'ui/shared/TruncatedValue';
interface Props {
data: VerifiedContract;
......@@ -56,9 +57,12 @@ const VerifiedContractsTableItem = ({ data, isLoading }: Props) => {
/>
</Td>
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" my={ 1 }>
{ balance }
</Skeleton>
<TruncatedValue
value={ balance }
isLoading={ isLoading }
my={ 1 }
w="100%"
/>
</Td>
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" my={ 1 }>
......
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