diff --git a/configs/app/ui/views/address.ts b/configs/app/ui/views/address.ts index c2f0f4fb52..088d288deb 100644 --- a/configs/app/ui/views/address.ts +++ b/configs/app/ui/views/address.ts @@ -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 = (() => { + 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>(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; diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index 1c215e2552..a4daf66371 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -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().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().oneOf(SMART_CONTRACT_EXTRA_VERIFICATION_METHODS)); + + return isNoneSchema.isValidSync(data) || isArrayOfMethodsSchema.isValidSync(data); + }), NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS: yup .array() .transform(replaceQuotes) diff --git a/deploy/tools/envs-validator/test/.env.alt b/deploy/tools/envs-validator/test/.env.alt index b51e366685..62183782bf 100644 --- a/deploy/tools/envs-validator/test/.env.alt +++ b/deploy/tools/envs-validator/test/.env.alt @@ -1,2 +1,3 @@ NEXT_PUBLIC_GRAPHIQL_TRANSACTION=none -NEXT_PUBLIC_API_SPEC_URL=none \ No newline at end of file +NEXT_PUBLIC_API_SPEC_URL=none +NEXT_PUBLIC_VIEWS_CONTRACT_EXTRA_VERIFICATION_METHODS=none \ No newline at end of file diff --git a/deploy/tools/envs-validator/test/.env.base b/deploy/tools/envs-validator/test/.env.base index 9eee5b327a..607ff38d36 100644 --- a/deploy/tools/envs-validator/test/.env.base +++ b/deploy/tools/envs-validator/test/.env.base @@ -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'] diff --git a/docs/ENVS.md b/docs/ENVS.md index 629109df8b..830252673c 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -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` | 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 | diff --git a/icons/clock-light.svg b/icons/clock-light.svg index 785174078b..9b18072460 100644 --- a/icons/clock-light.svg +++ b/icons/clock-light.svg @@ -1,11 +1,3 @@ - - - - - - - - - - + + diff --git a/icons/gas.svg b/icons/gas.svg index d199870ab9..4334fe93f5 100644 --- a/icons/gas.svg +++ b/icons/gas.svg @@ -1,3 +1,10 @@ - + + + + + + + + diff --git a/lib/api/resources.ts b/lib/api/resources.ts index eb51e9dc42..3f1d6cf6f1 100644 --- a/lib/api/resources.ts +++ b/lib/api/resources.ts @@ -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 : diff --git a/lib/hooks/useTimeAgoIncrement.tsx b/lib/hooks/useTimeAgoIncrement.tsx index 270bada27e..9d0300056d 100644 --- a/lib/hooks/useTimeAgoIncrement.tsx +++ b/lib/hooks/useTimeAgoIncrement.tsx @@ -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); diff --git a/mocks/stats/index.ts b/mocks/stats/index.ts index e6fecc8d98..0f0d408e7a 100644 --- a/mocks/stats/index.ts +++ b/mocks/stats/index.ts @@ -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', diff --git a/nextjs/getServerSideProps.ts b/nextjs/getServerSideProps.ts index 63103ae355..05733b177b 100644 --- a/nextjs/getServerSideProps.ts +++ b/nextjs/getServerSideProps.ts @@ -144,6 +144,16 @@ export const apiDocs: GetServerSideProps = async(context) => { return base(context); }; +export const graphIQl: GetServerSideProps = async(context) => { + if (!config.features.graphqlApiDocs.isEnabled) { + return { + notFound: true, + }; + } + + return base(context); +}; + export const csvExport: GetServerSideProps = async(context) => { if (!config.features.csvExport.isEnabled) { return { diff --git a/pages/graphiql.tsx b/pages/graphiql.tsx index 2521af804a..8bcff9cf93 100644 --- a/pages/graphiql.tsx +++ b/pages/graphiql.tsx @@ -27,4 +27,4 @@ const Page: NextPage = () => { export default Page; -export { base as getServerSideProps } from 'nextjs/getServerSideProps'; +export { graphIQl as getServerSideProps } from 'nextjs/getServerSideProps'; diff --git a/types/api/contract.ts b/types/api/contract.ts index 1991f25ead..845aa84b32 100644 --- a/types/api/contract.ts +++ b/types/api/contract.ts @@ -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; } -export interface SmartContractVerificationConfig extends SmartContractVerificationConfigRaw { - verification_options: Array; -} - export type SmartContractVerificationResponse = { status: 'error'; errors: SmartContractVerificationError; diff --git a/types/client/contract.ts b/types/client/contract.ts index 63116a4072..66fca3531c 100644 --- a/types/client/contract.ts +++ b/types/client/contract.ts @@ -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; +} diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-error-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-error-1.png deleted file mode 100644 index b96ceac2e2..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-error-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-success-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-success-1.png deleted file mode 100644 index d5902ddf0e..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_complex-success-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_default-error-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_default-error-1.png deleted file mode 100644 index cd23d7452d..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_default-error-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_error-with-code-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_error-with-code-1.png deleted file mode 100644 index e5d2fcf25c..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_error-with-code-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_raw-error-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_raw-error-1.png deleted file mode 100644 index 241bb2f7e3..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_raw-error-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_success-1.png b/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_success-1.png deleted file mode 100644 index ab0f9ab157..0000000000 Binary files a/ui/address/contract/methods/form/__screenshots__/ContractMethodResultApi.pw.tsx_default_success-1.png and /dev/null differ diff --git a/ui/address/contract/methods/form/resultPublicClient/ItemPrimitive.tsx b/ui/address/contract/methods/form/resultPublicClient/ItemPrimitive.tsx index 45914e1f0f..377c78eb7f 100644 --- a/ui/address/contract/methods/form/resultPublicClient/ItemPrimitive.tsx +++ b/ui/address/contract/methods/form/resultPublicClient/ItemPrimitive.tsx @@ -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 ( { castValueToString(data) } diff --git a/ui/address/mud/AddressMudRecord.tsx b/ui/address/mud/AddressMudRecord.tsx index 0b3ef6df93..b47ae5657b 100644 --- a/ui/address/mud/AddressMudRecord.tsx +++ b/ui/address/mud/AddressMudRecord.tsx @@ -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 error message; + return ; } return ( diff --git a/ui/address/mud/AddressMudRecordsTable.tsx b/ui/address/mud/AddressMudRecordsTable.tsx index aa829b2c2a..099bf924ca 100644 --- a/ui/address/mud/AddressMudRecordsTable.tsx +++ b/ui/address/mud/AddressMudRecordsTable.tsx @@ -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(isMobile ? 2 : 0); + const [ colsCutCount, setColsCutCount ] = React.useState(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(); diff --git a/ui/address/mud/AddressMudTable.tsx b/ui/address/mud/AddressMudTable.tsx index e106a17004..64ad615dc3 100644 --- a/ui/address/mud/AddressMudTable.tsx +++ b/ui/address/mud/AddressMudTable.tsx @@ -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; isQueryEnabled?: boolean; @@ -65,10 +68,10 @@ 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) { @@ -76,7 +79,7 @@ const AddressMudTable = ({ scrollRef, tableId, isQueryEnabled = true }: Props) = } const filtersTags = hasActiveFilters ? ( - + { 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 ? ( - { addressBalanceChunks[0] } - { addressBalanceChunks[1] && . } + { addressBalanceChunks[0] + (addressBalanceChunks[1] ? '.' : '') } { addressBalanceChunks[1] } diff --git a/ui/contractVerification/ContractVerificationForm.pw.tsx b/ui/contractVerification/ContractVerificationForm.pw.tsx index 03398fb2ea..9aa07c10e5 100644 --- a/ui/contractVerification/ContractVerificationForm.pw.tsx +++ b/ui/contractVerification/ContractVerificationForm.pw.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type { SmartContractVerificationConfig } from 'types/api/contract'; +import type { SmartContractVerificationConfig } from 'types/client/contract'; import * as socketServer from 'playwright/fixtures/socketServer'; import { test, expect } from 'playwright/lib'; @@ -37,6 +37,8 @@ const formConfig: SmartContractVerificationConfig = { 'vyper-code', 'vyper-multi-part', 'vyper-standard-input', + 'solidity-hardhat', + 'solidity-foundry', ], vyper_compiler_versions: [ 'v0.3.7+commit.6020b8bb', @@ -82,7 +84,7 @@ test('flatten source code method +@dark-mode +@mobile', async({ render, page }) // select method await component.getByLabel(/verification method/i).focus(); await component.getByLabel(/verification method/i).fill('solidity'); - await page.getByRole('button', { name: /flattened source code/i }).click(); + await page.getByRole('button', { name: /single file/i }).click(); await page.getByText(/add contract libraries/i).click(); await page.locator('button[aria-label="add"]').click(); @@ -191,3 +193,25 @@ test('vyper vyper-standard-input method', async({ render, page }) => { await expect(component).toHaveScreenshot(); }); + +test('solidity-hardhat method', async({ render, page }) => { + const component = await render(, { hooksConfig }); + + // select method + await component.getByLabel(/verification method/i).focus(); + await component.getByLabel(/verification method/i).fill('hardhat'); + await page.getByRole('button', { name: /hardhat/i }).click(); + + await expect(component).toHaveScreenshot(); +}); + +test('solidity-foundry method', async({ render, page }) => { + const component = await render(, { hooksConfig }); + + // select method + await component.getByLabel(/verification method/i).focus(); + await component.getByLabel(/verification method/i).fill('foundry'); + await page.getByRole('button', { name: /foundry/i }).click(); + + await expect(component).toHaveScreenshot(); +}); diff --git a/ui/contractVerification/ContractVerificationForm.tsx b/ui/contractVerification/ContractVerificationForm.tsx index 8b77e1010c..c8e6a85057 100644 --- a/ui/contractVerification/ContractVerificationForm.tsx +++ b/ui/contractVerification/ContractVerificationForm.tsx @@ -5,7 +5,8 @@ import { useForm, FormProvider } from 'react-hook-form'; import type { FormFields } from './types'; import type { SocketMessage } from 'lib/socket/types'; -import type { SmartContractVerificationMethod, SmartContractVerificationConfig, SmartContract } from 'types/api/contract'; +import type { SmartContract, SmartContractVerificationMethodApi } from 'types/api/contract'; +import type { SmartContractVerificationConfig } from 'types/client/contract'; import { route } from 'nextjs-routes'; @@ -22,6 +23,8 @@ import ContractVerificationFieldLicenseType from './fields/ContractVerificationF import ContractVerificationFieldMethod from './fields/ContractVerificationFieldMethod'; import ContractVerificationFlattenSourceCode from './methods/ContractVerificationFlattenSourceCode'; import ContractVerificationMultiPartFile from './methods/ContractVerificationMultiPartFile'; +import ContractVerificationSolidityFoundry from './methods/ContractVerificationSolidityFoundry'; +import ContractVerificationSolidityHardhat from './methods/ContractVerificationSolidityHardhat'; import ContractVerificationSourcify from './methods/ContractVerificationSourcify'; import ContractVerificationStandardInput from './methods/ContractVerificationStandardInput'; import ContractVerificationVyperContract from './methods/ContractVerificationVyperContract'; @@ -30,7 +33,7 @@ import ContractVerificationVyperStandardInput from './methods/ContractVerificati import { prepareRequestBody, formatSocketErrors, getDefaultValues, METHOD_LABELS } from './utils'; interface Props { - method?: SmartContractVerificationMethod; + method?: SmartContractVerificationMethodApi; config: SmartContractVerificationConfig; hash?: string; } @@ -159,6 +162,8 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro 'vyper-code': , 'vyper-multi-part': , 'vyper-standard-input': , + 'solidity-hardhat': , + 'solidity-foundry': , }; }, [ config ]); const method = watch('method'); @@ -193,7 +198,7 @@ const ContractVerificationForm = ({ method: methodFromQuery, config, hash }: Pro /> { content } - { Boolean(method) && ( + { Boolean(method) && method.value !== 'solidity-hardhat' && method.value !== 'solidity-foundry' && (