Skip to content

Commit

Permalink
Showing 73 changed files with 437 additions and 192 deletions.
18 changes: 18 additions & 0 deletions configs/app/ui/views/address.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { SmartContractVerificationMethodExtra } from 'types/client/contract';
import { SMART_CONTRACT_EXTRA_VERIFICATION_METHODS } from 'types/client/contract';
import type { AddressViewId, IdenticonType } from 'types/views/address';
import { ADDRESS_VIEWS_IDS, IDENTICON_TYPES } from 'types/views/address';

@@ -24,10 +26,26 @@ const hiddenViews = (() => {
return result;
})();

const extraVerificationMethods: Array<SmartContractVerificationMethodExtra> = (() => {
const envValue = getEnvValue('NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS');
if (envValue === 'none') {
return [];
}

if (!envValue) {
return SMART_CONTRACT_EXTRA_VERIFICATION_METHODS;
}

const parsedMethods = parseEnvJson<Array<SmartContractVerificationMethodExtra>>(getEnvValue('NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS')) || [];

return SMART_CONTRACT_EXTRA_VERIFICATION_METHODS.filter((method) => parsedMethods.includes(method));
})();

const config = Object.freeze({
identiconType,
hiddenViews,
solidityscanEnabled: getEnvValue('NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED') === 'true',
extraVerificationMethods,
});

export default config;
18 changes: 17 additions & 1 deletion deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-len */
declare module 'yup' {
interface StringSchema {
// Yup's URL validator is not perfect so we made our own
@@ -11,7 +12,7 @@ import * as yup from 'yup';
import type { AdButlerConfig } from '../../../types/client/adButlerConfig';
import { SUPPORTED_AD_TEXT_PROVIDERS, SUPPORTED_AD_BANNER_PROVIDERS, SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS } from '../../../types/client/adProviders';
import type { AdTextProviders, AdBannerProviders, AdBannerAdditionalProviders } from '../../../types/client/adProviders';
import type { ContractCodeIde } from '../../../types/client/contract';
import { SMART_CONTRACT_EXTRA_VERIFICATION_METHODS, type ContractCodeIde, type SmartContractVerificationMethodExtra } from '../../../types/client/contract';
import type { DeFiDropdownItem } from '../../../types/client/deFiDropdown';
import type { GasRefuelProviderConfig } from '../../../types/client/gasRefuelProviderConfig';
import { GAS_UNITS } from '../../../types/client/gasTracker';
@@ -576,6 +577,21 @@ const schema = yup
.json()
.of(yup.string<AddressViewId>().oneOf(ADDRESS_VIEWS_IDS)),
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED: yup.boolean(),
NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS: yup
.mixed()
.test(
'shape',
'Invalid schema were provided for NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS, it should be either array of method ids or "none" string literal',
(data) => {
const isNoneSchema = yup.string().oneOf([ 'none' ]);
const isArrayOfMethodsSchema = yup
.array()
.transform(replaceQuotes)
.json()
.of(yup.string<SmartContractVerificationMethodExtra>().oneOf(SMART_CONTRACT_EXTRA_VERIFICATION_METHODS));

return isNoneSchema.isValidSync(data) || isArrayOfMethodsSchema.isValidSync(data);
}),
NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS: yup
.array()
.transform(replaceQuotes)
3 changes: 2 additions & 1 deletion deploy/tools/envs-validator/test/.env.alt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=none
NEXT_PUBLIC_API_SPEC_URL=none
NEXT_PUBLIC_API_SPEC_URL=none
NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS=none
1 change: 1 addition & 0 deletions deploy/tools/envs-validator/test/.env.base
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@ NEXT_PUBLIC_STATS_API_BASE_PATH=/
NEXT_PUBLIC_USE_NEXT_JS_PROXY=false
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar
NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS=['top_accounts']
NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS=['solidity-hardhat','solidity-foundry']
NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees','total_reward']
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'NFT Marketplace','collection_url':'https://example.com/{hash}','instance_url':'https://example.com/{hash}/{id}','logo_url':'https://example.com/logo.png'}]
NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS=['fee_per_gas']
1 change: 1 addition & 0 deletions docs/ENVS.md
Original file line number Diff line number Diff line change
@@ -221,6 +221,7 @@ Settings for meta tags, OG tags and SEO
| NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE | `"github" \| "jazzicon" \| "gradient_avatar" \| "blockie"` | Default style of address identicon appearance. Choose between [GitHub](https://github.blog/2013-08-14-identicons/), [Metamask Jazzicon](https://metamask.github.io/jazzicon/), [Gradient Avatar](https://github.com/varld/gradient-avatar) and [Ethereum Blocky](https://mycryptohq.github.io/ethereum-blockies-base64/) | - | `jazzicon` | `gradient_avatar` | v1.12.0+ |
| NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS | `Array<AddressViewId>` | Address views that should not be displayed. See below the list of the possible id values. | - | - | `'["top_accounts"]'` | v1.15.0+ |
| NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED | `boolean` | Set to `true` if SolidityScan reports are supported | - | - | `true` | v1.19.0+ |
| NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS | `Array<'solidity-hardhat' \| 'solidity-foundry'>` | Pass an array of additional methods from which users can choose while verifying a smart contract. Both methods are available by default, pass `'none'` string to disable them all. | - | - | `['solidity-hardhat']` | v1.33.0+ |

##### Address views list
| Id | Description |
12 changes: 2 additions & 10 deletions icons/clock-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion icons/gas.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions lib/api/resources.ts
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ import type { ChartMarketResponse, ChartSecondaryCoinPriceResponse, ChartTransac
import type { BackendVersionConfig } from 'types/api/configs';
import type {
SmartContract,
SmartContractVerificationConfig,
SmartContractVerificationConfigRaw,
SolidityscanReport,
SmartContractSecurityAudits,
} from 'types/api/contract';
@@ -1028,7 +1028,7 @@ Q extends 'contract_solidityscan_report' ? SolidityscanReport :
Q extends 'verified_contracts' ? VerifiedContractsResponse :
Q extends 'verified_contracts_counters' ? VerifiedContractsCounters :
Q extends 'visualize_sol2uml' ? visualizer.VisualizeResponse :
Q extends 'contract_verification_config' ? SmartContractVerificationConfig :
Q extends 'contract_verification_config' ? SmartContractVerificationConfigRaw :
Q extends 'withdrawals' ? WithdrawalsResponse :
Q extends 'withdrawals_counters' ? WithdrawalsCounters :
Q extends 'optimistic_l2_output_roots' ? OptimisticL2OutputRootsResponse :
2 changes: 2 additions & 0 deletions lib/hooks/useTimeAgoIncrement.tsx
Original file line number Diff line number Diff line change
@@ -78,6 +78,8 @@ export default function useTimeAgoIncrement(ts: string | null, isEnabled?: boole

isEnabled && startIncrement();

!isEnabled && setValue(dayjs(ts).fromNow());

return () => {
timeouts.forEach(window.clearTimeout);
intervals.forEach(window.clearInterval);
5 changes: 5 additions & 0 deletions mocks/stats/index.ts
Original file line number Diff line number Diff line change
@@ -64,6 +64,11 @@ export const withoutBothPrices: HomeStats = {
gas_prices: _mapValues(base.gas_prices, (price) => price ? ({ ...price, price: null, fiat_price: null }) : null),
};

export const withoutGasInfo: HomeStats = {
...base,
gas_prices: null,
};

export const withSecondaryCoin: HomeStats = {
...base,
secondary_coin_price: '3.398',
10 changes: 10 additions & 0 deletions nextjs/getServerSideProps.ts
Original file line number Diff line number Diff line change
@@ -144,6 +144,16 @@ export const apiDocs: GetServerSideProps<Props> = async(context) => {
return base(context);
};

export const graphIQl: GetServerSideProps<Props> = async(context) => {
if (!config.features.graphqlApiDocs.isEnabled) {
return {
notFound: true,
};
}

return base(context);
};

export const csvExport: GetServerSideProps<Props> = async(context) => {
if (!config.features.csvExport.isEnabled) {
return {
2 changes: 1 addition & 1 deletion pages/graphiql.tsx
Original file line number Diff line number Diff line change
@@ -27,4 +27,4 @@ const Page: NextPage = () => {

export default Page;

export { base as getServerSideProps } from 'nextjs/getServerSideProps';
export { graphIQl as getServerSideProps } from 'nextjs/getServerSideProps';
6 changes: 1 addition & 5 deletions types/api/contract.ts
Original file line number Diff line number Diff line change
@@ -75,7 +75,7 @@ export interface SmartContractExternalLibrary {

// VERIFICATION

export type SmartContractVerificationMethod = 'flattened-code' | 'standard-input' | 'sourcify' | 'multi-part'
export type SmartContractVerificationMethodApi = 'flattened-code' | 'standard-input' | 'sourcify' | 'multi-part'
| 'vyper-code' | 'vyper-multi-part' | 'vyper-standard-input';

export interface SmartContractVerificationConfigRaw {
@@ -88,10 +88,6 @@ export interface SmartContractVerificationConfigRaw {
license_types: Record<SmartContractLicenseType, number>;
}

export interface SmartContractVerificationConfig extends SmartContractVerificationConfigRaw {
verification_options: Array<SmartContractVerificationMethod>;
}

export type SmartContractVerificationResponse = {
status: 'error';
errors: SmartContractVerificationError;
15 changes: 14 additions & 1 deletion types/client/contract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SmartContractLicenseType } from 'types/api/contract';
import type { SmartContractLicenseType, SmartContractVerificationConfigRaw, SmartContractVerificationMethodApi } from 'types/api/contract';

export interface ContractCodeIde {
title: string;
@@ -12,3 +12,16 @@ export interface ContractLicense {
label: string;
title: string;
}

export const SMART_CONTRACT_EXTRA_VERIFICATION_METHODS = [
'solidity-hardhat' as const,
'solidity-foundry' as const,
];

export type SmartContractVerificationMethodExtra = (typeof SMART_CONTRACT_EXTRA_VERIFICATION_METHODS)[number];

export type SmartContractVerificationMethod = SmartContractVerificationMethodApi | SmartContractVerificationMethodExtra;

export interface SmartContractVerificationConfig extends SmartContractVerificationConfigRaw {
verification_options: Array<SmartContractVerificationMethod>;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import type { AbiParameter } from 'viem';

import { route } from 'nextjs-routes';

import { WEI } from 'lib/consts';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import LinkInternal from 'ui/shared/links/LinkInternal';

@@ -51,7 +52,7 @@ const ItemPrimitive = ({ abiParameter, data, level, hideLabel }: Props) => {

const intMatch = matchInt(abiParameter.type);
if (intMatch && typeof data === 'bigint' && intMatch.max > INT_TOOLTIP_THRESHOLD && data > INT_TOOLTIP_THRESHOLD) {
const dividedValue = BigNumber(data.toString()).div(BigNumber(INT_TOOLTIP_THRESHOLD));
const dividedValue = BigNumber(data.toString()).div(WEI);
return (
<Tooltip label={ dividedValue.toLocaleString() + ' ETH' }>
<span>{ castValueToString(data) }</span>
3 changes: 2 additions & 1 deletion ui/address/mud/AddressMudRecord.tsx
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import useApiQuery from 'lib/api/useApiQuery';
import dayjs from 'lib/date/dayjs';
import getQueryParamString from 'lib/router/getQueryParamString';
import ContentLoader from 'ui/shared/ContentLoader';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import TruncatedValue from 'ui/shared/TruncatedValue';

import AddressMudBreadcrumbs from './AddressMudBreadcrumbs';
@@ -36,7 +37,7 @@ const AddressMudRecord = ({ tableId, recordId, isQueryEnabled = true, scrollRef
}

if (isError) {
return <Box>error message</Box>;
return <DataFetchAlert/>;
}

return (
17 changes: 10 additions & 7 deletions ui/address/mud/AddressMudRecordsTable.tsx
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ const AddressMudRecordsTable = ({
}: Props) => {
const totalColsCut = data.schema.key_names.length + data.schema.value_names.length;
const isMobile = useIsMobile(false);
const [ colsCutCount, setColsCutCount ] = React.useState<number>(isMobile ? 2 : 0);
const [ colsCutCount, setColsCutCount ] = React.useState<number>(isMobile ? MIN_CUT_COUNT : 0);
const [ isOpened, setIsOpened ] = useBoolean(false);
const [ hasCut, setHasCut ] = useBoolean(isMobile ? totalColsCut > MIN_CUT_COUNT : true);

@@ -70,11 +70,14 @@ const AddressMudRecordsTable = ({

e.preventDefault();

router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: data.table.table_id, record_id: e.currentTarget.getAttribute('data-id') as string } },
undefined,
{ shallow: true },
);
const recordId = e.currentTarget.getAttribute('data-id');
if (recordId) {
router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: data.table.table_id, record_id: recordId } },
undefined,
{ shallow: true },
);
}
scrollRef?.current?.scrollIntoView();
}, [ router, scrollRef, hash, data.table.table_id ]);

@@ -96,7 +99,7 @@ const AddressMudRecordsTable = ({
React.useEffect(() => {
if (hasCut && !colsCutCount && containerRef.current) {
const count = Math.floor((containerRef.current.getBoundingClientRect().width - CUT_COL_WIDTH) / COL_MIN_WIDTH);
if (totalColsCut > 2 && count - 1 < totalColsCut) {
if (totalColsCut > MIN_CUT_COUNT && count - 1 < totalColsCut) {
setColsCutCount(count - 1);
} else {
setHasCut.off();
13 changes: 8 additions & 5 deletions ui/address/mud/AddressMudTable.tsx
Original file line number Diff line number Diff line change
@@ -19,6 +19,9 @@ import AddressMudBreadcrumbs from './AddressMudBreadcrumbs';
import AddressMudRecordsTable from './AddressMudRecordsTable';
import { getNameTypeText, SORT_SEQUENCE } from './utils';

const BREADCRUMBS_HEIGHT = 60;
const FILTERS_HEIGHT = 44;

type Props ={
scrollRef?: React.RefObject<HTMLDivElement>;
isQueryEnabled?: boolean;
@@ -65,18 +68,18 @@ const AddressMudTable = ({ scrollRef, tableId, isQueryEnabled = true }: Props) =

const hasActiveFilters = Object.values(filters).some(Boolean);

const actionBatHeight = React.useMemo(() => {
const heightWithoutFilters = pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : 60;
const actionBarHeight = React.useMemo(() => {
const heightWithoutFilters = pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : BREADCRUMBS_HEIGHT;

return hasActiveFilters ? heightWithoutFilters + 44 : heightWithoutFilters;
return hasActiveFilters ? heightWithoutFilters + FILTERS_HEIGHT : heightWithoutFilters;
}, [ pagination.isVisible, hasActiveFilters ]);

if (isLoading) {
return <ContentLoader/>;
}

const filtersTags = hasActiveFilters ? (
<HStack gap={ 3 } mb={ 1 }>
<HStack gap={ 3 } mb={ 1 } flexWrap="wrap">
{ Object.entries(filters).map(([ key, value ]) => {
const index = key as FilterKeys === 'filter_key0' ? 0 : 1;
return (
@@ -118,7 +121,7 @@ const AddressMudTable = ({ scrollRef, tableId, isQueryEnabled = true }: Props) =
const content = data?.items ? (
<AddressMudRecordsTable
data={ data }
top={ actionBatHeight }
top={ actionBarHeight }
sorting={ sorting }
toggleSorting={ toggleSorting }
setFilters={ setFilters }
14 changes: 9 additions & 5 deletions ui/address/mud/AddressMudTablesListItem.tsx
Original file line number Diff line number Diff line change
@@ -32,11 +32,15 @@ const AddressMudTablesListItem = ({ item, isLoading, scrollRef, hash }: Props) =

e.preventDefault();

router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: e.currentTarget.getAttribute('data-id') as string } },
undefined,
{ shallow: true },
);
const tableId = e.currentTarget.getAttribute('data-id');
if (tableId) {
router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: tableId } },
undefined,
{ shallow: true },
);
}

scrollRef?.current?.scrollIntoView();
}, [ router, scrollRef, hash ]);

13 changes: 8 additions & 5 deletions ui/address/mud/AddressMudTablesTableItem.tsx
Original file line number Diff line number Diff line change
@@ -30,11 +30,14 @@ const AddressMudTablesTableItem = ({ item, isLoading, scrollRef, hash }: Props)

e.preventDefault();

router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: e.currentTarget.getAttribute('data-id') as string } },
undefined,
{ shallow: true },
);
const tableId = e.currentTarget.getAttribute('data-id');
if (tableId) {
router.push(
{ pathname: '/address/[hash]', query: { hash, tab: 'mud', table_id: tableId } },
undefined,
{ shallow: true },
);
}
scrollRef?.current?.scrollIntoView();
}, [ router, scrollRef, hash ]);

3 changes: 1 addition & 2 deletions ui/addresses/AddressesTableItem.tsx
Original file line number Diff line number Diff line change
@@ -49,8 +49,7 @@ const AddressesTableItem = ({
</Td>
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" maxW="100%">
<Text lineHeight="24px" as="span">{ addressBalanceChunks[0] }</Text>
{ addressBalanceChunks[1] && <Text lineHeight="24px" as="span">.</Text> }
<Text lineHeight="24px" as="span">{ addressBalanceChunks[0] + (addressBalanceChunks[1] ? '.' : '') }</Text>
<Text lineHeight="24px" variant="secondary" as="span">{ addressBalanceChunks[1] }</Text>
</Skeleton>
</Td>
Loading

0 comments on commit 0255649

Please sign in to comment.