Skip to content

Commit

Permalink
additional form fields
Browse files Browse the repository at this point in the history
  • Loading branch information
tom2drum committed Aug 13, 2024
1 parent d6e0615 commit ff1b878
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 2 deletions.
1 change: 1 addition & 0 deletions types/api/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export interface SmartContractVerificationConfigRaw {
vyper_evm_versions: Array<string>;
is_rust_verifier_microservice_enabled: boolean;
license_types: Record<SmartContractLicenseType, number>;
zk_compiler_versions?: Array<string>;
}

export type SmartContractVerificationResponse = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Box, Link } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
import type { ControllerRenderProps } from 'react-hook-form';
import { useFormContext, Controller } from 'react-hook-form';

import type { FormFields } from '../types';
import type { SmartContractVerificationConfig } from 'types/client/contract';

import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import FancySelect from 'ui/shared/FancySelect/FancySelect';
import IconSvg from 'ui/shared/IconSvg';

import ContractVerificationFormRow from '../ContractVerificationFormRow';

const OPTIONS_LIMIT = 50;

const ContractVerificationFieldZkCompiler = () => {
const { formState, control } = useFormContext<FormFields>();
const isMobile = useIsMobile();
const queryClient = useQueryClient();
const config = queryClient.getQueryData<SmartContractVerificationConfig>(getResourceKey('contract_verification_config'));

const options = React.useMemo(() => (
config?.zk_compiler_versions?.map((option) => ({ label: option, value: option })) || []
), [ config?.zk_compiler_versions ]);

const loadOptions = React.useCallback(async(inputValue: string) => {
return options
.filter(({ label }) => !inputValue || label.toLowerCase().includes(inputValue.toLowerCase()))
.slice(0, OPTIONS_LIMIT);
}, [ options ]);

const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<FormFields, 'zk_compiler'>}) => {
const error = 'zk_compiler' in formState.errors ? formState.errors.zk_compiler : undefined;

return (
<FancySelect
{ ...field }
loadOptions={ loadOptions }
defaultOptions
size={ isMobile ? 'md' : 'lg' }
placeholder="ZK compiler (enter version or use the dropdown)"
placeholderIcon={ <IconSvg name="search"/> }
isDisabled={ formState.isSubmitting }
error={ error }
isRequired
isAsync
/>
);
}, [ formState.errors, formState.isSubmitting, isMobile, loadOptions ]);

return (
<ContractVerificationFormRow>
<Controller
name="zk_compiler"
control={ control }
render={ renderControl }
rules={{ required: true }}
/>
<Box>
<Link isExternal href="https://docs.zksync.io/zk-stack/components/compiler/specification#glossary">zksolc</Link>
<span> compiler version.</span>
</Box>
</ContractVerificationFormRow>
);
};

export default React.memo(ContractVerificationFieldZkCompiler);
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Flex, Select } from '@chakra-ui/react';
import React from 'react';
import type { ControllerRenderProps } from 'react-hook-form';
import { Controller, useFormContext } from 'react-hook-form';

import type { FormFields } from '../types';

import CheckboxInput from 'ui/shared/CheckboxInput';

import ContractVerificationFormRow from '../ContractVerificationFormRow';

const ContractVerificationFieldZkOptimization = () => {
const [ isEnabled, setIsEnabled ] = React.useState(false);
const { formState, control } = useFormContext<FormFields>();

const error = 'optimization_mode' in formState.errors ? formState.errors.optimization_mode : undefined;

const handleCheckboxChange = React.useCallback(() => {
setIsEnabled(prev => !prev);
}, []);

const renderCheckboxControl = React.useCallback(({ field }: {field: ControllerRenderProps<FormFields, 'is_optimization_enabled'>}) => (
<Flex flexShrink={ 0 }>
<CheckboxInput<FormFields, 'is_optimization_enabled'>
text="Optimization enabled"
field={ field }
onChange={ handleCheckboxChange }
isDisabled={ formState.isSubmitting }
/>
</Flex>
), [ formState.isSubmitting, handleCheckboxChange ]);

const renderInputControl = React.useCallback(({ field }: {field: ControllerRenderProps<FormFields, 'optimization_mode'>}) => {
return (
<Select
size="xs"
{ ...field }
w="auto"
borderRadius="base"
isDisabled={ formState.isSubmitting }
placeholder="Optimization mode"
isInvalid={ Boolean(error) }
>
{ [ '0', '1', '2', '3', 'z', 's' ].map((value) => (
<option key={ value } value={ value }>
{ value }
</option>
)) }
</Select>
);
}, [ error, formState.isSubmitting ]);

return (
<ContractVerificationFormRow>
<Flex columnGap={ 5 } rowGap={ 2 } h={{ base: 'auto', lg: '32px' }} flexDir={{ base: 'column', lg: 'row' }}>
<Controller
name="is_optimization_enabled"
control={ control }
render={ renderCheckboxControl }
/>
{ isEnabled && (
<Controller
name="optimization_mode"
control={ control }
render={ renderInputControl }
rules={{ required: true }}
/>
) }
</Flex>
</ContractVerificationFormRow>
);
};

export default React.memo(ContractVerificationFieldZkOptimization);
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,32 @@ import React from 'react';

import type { SmartContractVerificationConfig } from 'types/client/contract';

import config from 'configs/app';

import ContractVerificationMethod from '../ContractVerificationMethod';
import ContractVerificationFieldAutodetectArgs from '../fields/ContractVerificationFieldAutodetectArgs';
import ContractVerificationFieldCompiler from '../fields/ContractVerificationFieldCompiler';
import ContractVerificationFieldName from '../fields/ContractVerificationFieldName';
import ContractVerificationFieldSources from '../fields/ContractVerificationFieldSources';
import ContractVerificationFieldZkCompiler from '../fields/ContractVerificationFieldZkCompiler';
import ContractVerificationFieldZkOptimization from '../fields/ContractVerificationFieldZkOptimization';

const FILE_TYPES = [ '.json' as const ];
const rollupFeature = config.features.rollup;

const ContractVerificationStandardInput = ({ config }: { config: SmartContractVerificationConfig }) => {
return (
<ContractVerificationMethod title="Contract verification via Solidity (standard JSON input) ">
{ !config?.is_rust_verifier_microservice_enabled && <ContractVerificationFieldName/> }
<ContractVerificationFieldCompiler/>
{ rollupFeature.isEnabled && rollupFeature.type === 'zkSync' && <ContractVerificationFieldZkCompiler/> }
<ContractVerificationFieldSources
fileTypes={ FILE_TYPES }
title="Standard Input JSON"
hint="Upload the standard input JSON file created during contract compilation."
required
/>
{ rollupFeature.isEnabled && rollupFeature.type === 'zkSync' && <ContractVerificationFieldZkOptimization/> }
{ !config?.is_rust_verifier_microservice_enabled && <ContractVerificationFieldAutodetectArgs/> }
</ContractVerificationMethod>
);
Expand Down
16 changes: 15 additions & 1 deletion ui/contractVerification/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ export interface FormFieldsStandardInput {
license_type: LicenseOption | null;
}

export interface FormFieldsStandardInputZk {
address: string;
method: MethodOption;
name: string;
compiler: Option | null;
zk_compiler: Option | null;
sources: Array<File>;
autodetect_constructor_args: boolean;
constructor_args: string;
license_type: LicenseOption | null;
is_optimization_enabled: boolean;
optimization_mode: string | undefined;
}

export interface FormFieldsSourcify {
address: string;
method: MethodOption;
Expand Down Expand Up @@ -93,5 +107,5 @@ export interface FormFieldsVyperStandardInput {
license_type: LicenseOption | null;
}

export type FormFields = FormFieldsFlattenSourceCode | FormFieldsStandardInput | FormFieldsSourcify |
export type FormFields = FormFieldsFlattenSourceCode | FormFieldsStandardInput | FormFieldsStandardInputZk | FormFieldsSourcify |
FormFieldsMultiPartFile | FormFieldsVyperContract | FormFieldsVyperMultiPartFile | FormFieldsVyperStandardInput;
12 changes: 11 additions & 1 deletion ui/contractVerification/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
FormFieldsMultiPartFile,
FormFieldsSourcify,
FormFieldsStandardInput,
FormFieldsStandardInputZk,
FormFieldsVyperContract,
FormFieldsVyperMultiPartFile,
FormFieldsVyperStandardInput,
Expand Down Expand Up @@ -223,7 +224,7 @@ export function prepareRequestBody(data: FormFields): FetchParams['body'] {
}

case 'standard-input': {
const _data = data as FormFieldsStandardInput;
const _data = data as (FormFieldsStandardInput | FormFieldsStandardInputZk);

const body = new FormData();
_data.compiler && body.set('compiler_version', _data.compiler.value);
Expand All @@ -233,6 +234,15 @@ export function prepareRequestBody(data: FormFields): FetchParams['body'] {
body.set('constructor_args', _data.constructor_args);
addFilesToFormData(body, _data.sources, 'files');

// zkSync fields
'zk_compiler' in _data && _data.zk_compiler && body.set('zk_compiler_version', _data.zk_compiler.value);
if ('is_optimization_enabled' in _data) {
body.set('is_optimization_enabled', String(Boolean(_data.is_optimization_enabled)));
if (_data.is_optimization_enabled && 'optimization_mode' in _data && _data.optimization_mode) {
body.set('optimization_runs', _data.optimization_mode);
}
}

return body;
}

Expand Down

0 comments on commit ff1b878

Please sign in to comment.