Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve constructor args, add optimizer config #1193

Merged
merged 2 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#1193](https://github.com/alleslabs/celatone-frontend/pull/1193) Add optimizer configuration to EVM contract verify page, fix constructor args, and Zod type
- [#1188](https://github.com/alleslabs/celatone-frontend/pull/1188) Add request and simulate evm tx
- [#1192](https://github.com/alleslabs/celatone-frontend/pull/1192) Add fixed bytes hex address util
- [#1189](https://github.com/alleslabs/celatone-frontend/pull/1189) Add constructor args to EVM contract verify page
Expand Down
10 changes: 7 additions & 3 deletions src/lib/components/forms/ControllerInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,13 @@ export const ControllerInput = <T extends FieldValues>({
{isError && (
<FormErrorMessage className="error-text">{error}</FormErrorMessage>
)}
<FormHelperText className="helper-text">
{status?.message ? getResponseMsg(status, helperText) : helperText}
</FormHelperText>
{(status?.message || helperText) && (
<FormHelperText className="helper-text">
{status?.message
? getResponseMsg(status, helperText)
: helperText}
</FormHelperText>
)}
</Flex>
{helperAction}
</Flex>
Expand Down
51 changes: 39 additions & 12 deletions src/lib/pages/evm-contract-verify/components/ConstructorArgs.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import { Checkbox, Heading, Stack, Text, Textarea } from "@chakra-ui/react";
import { Control, useController } from "react-hook-form";
import { Box, Checkbox, Heading, Stack, Text } from "@chakra-ui/react";
import { Control, useController, useWatch } from "react-hook-form";
import { EvmContractVerifyForm } from "../types";
import { ControllerTextarea } from "lib/components/forms";

interface ConstructorArgsProps {
control: Control<EvmContractVerifyForm>;
}

export const ConstructorArgs = ({ control }: ConstructorArgsProps) => {
const { field } = useController({
const { field: fieldEnabled } = useController({
control,
name: "verifyForm.form.constructorArgs.enabled",
});

const {
fieldState: { error },
} = useController({
control,
name: "verifyForm.form.constructorArgs.value",
});

const constructorArgs = useWatch({
control,
name: "verifyForm.form.constructorArgs",
});

return (
<Stack spacing={6}>
<Stack spacing={2}>
<Stack spacing={1}>
<Heading as="h6" variant="h6">
Input Constructor Arguments
Expand All @@ -23,17 +36,31 @@ export const ConstructorArgs = ({ control }: ConstructorArgsProps) => {
</Text>
</Stack>
<Checkbox
isChecked={field.value !== undefined}
onChange={(e) => field.onChange(e.target.checked ? "" : undefined)}
p={2}
isChecked={constructorArgs.enabled}
onChange={(e) => fieldEnabled.onChange(e.target.checked)}
>
<Text>Have constructor arguments</Text>
</Checkbox>
<Textarea
visibility={field.value === undefined ? "hidden" : "visible"}
placeholder="ex.000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239"
value={field.value}
onChange={(e) => field.onChange(e.target.value)}
/>
<Box
py={4}
px={3}
bgColor="gray.900"
borderRadius="md"
display={fieldEnabled.value ? "block" : "none"}
>
<ControllerTextarea
backgroundColor="gray.900"
name="verifyForm.form.constructorArgs.value"
control={control}
isRequired
label="Constructor Arguments"
placeholder="ex.000000000000000000000000c005dc82818d67af737725bd4bf75435d065d239"
variant="fixed-floating"
labelBgColor="gray.900"
error={error?.message}
/>
</Box>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
EvmProgrammingLanguage,
VerificationOptions,
} from "../types";
import { getVerifyFormInitialValue } from "./helper";

interface EvmContractVerifyVyperProps {
control: Control<EvmContractVerifyForm>;
Expand All @@ -13,25 +14,26 @@ interface EvmContractVerifyVyperProps {
export const EvmContractVerifyOptions = ({
control,
}: EvmContractVerifyVyperProps) => {
const { field: verifyFormOptionField } = useController({
const { field } = useController({
control,
name: "verifyForm.form.option",
name: "verifyForm.form",
});

const [language, verifyFormOption] = useWatch({
control,
name: ["verifyForm.language", "verifyForm.form.option"],
});

const handleOptionChange = (nextVal: VerificationOptions) => {
field.onChange(getVerifyFormInitialValue(language, nextVal));
};

return (
<Stack spacing={6}>
<Heading as="h6" variant="h6">
Select Verification Option
</Heading>
<RadioGroup
onChange={(nextVal) => verifyFormOptionField.onChange(nextVal)}
value={verifyFormOption}
>
<RadioGroup onChange={handleOptionChange} value={verifyFormOption}>
<Grid gridTemplateColumns="repeat(3, 1fr)" gap={4}>
{language === EvmProgrammingLanguage.Solidity && (
<Radio
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Checkbox, Flex, Heading, Stack, Text } from "@chakra-ui/react";
import { Control, useController, useWatch } from "react-hook-form";
import { EvmContractVerifyForm } from "../types";
import { ControllerInput } from "lib/components/forms";

interface OptimizerConfigurationProps {
control: Control<EvmContractVerifyForm>;
}

export const OptimizerConfiguration = ({
control,
}: OptimizerConfigurationProps) => {
const { field } = useController({
control,
name: "verifyForm.form.optimizerConfig",
});

const enabled = useWatch({
control,
name: "verifyForm.form.optimizerConfig.enabled",
});

return (
<Stack spacing={2}>
<Stack spacing={1}>
<Heading as="h6" variant="h6">
Optimization Configuration
</Heading>
<Text variant="body2" color="text.dark">
Provide optimization settings for the contract
</Text>
</Stack>
<Flex gap={4} pl={2} alignItems="center">
<Checkbox
isChecked={enabled}
onChange={(e) =>
field.onChange({ ...field.value, enabled: e.target.checked })
}
>
<Text>Optimization Enabled</Text>
</Checkbox>
<Flex gap={2} alignItems="center">
<Text color="text.disabled">Optimization Run:</Text>
<ControllerInput
width={125}
type="number"
name="verifyForm.form.optimizerConfig.runs"
isDisabled={!enabled}
control={control}
size="md"
/>
</Flex>
</Flex>
</Stack>
);
};
63 changes: 63 additions & 0 deletions src/lib/pages/evm-contract-verify/components/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { EvmProgrammingLanguage, VerificationOptions } from "../types";

export const getVerifyFormInitialValue = (
language: EvmProgrammingLanguage,
verificationOption: VerificationOptions
) => {
const constructorArgs = {
enabled: false,
value: "",
};

const optimizerConfig = {
enabled: false,
runs: 200,
};

if (language === EvmProgrammingLanguage.Solidity) {
switch (verificationOption) {
case VerificationOptions.UploadFiles:
return {
option: verificationOption,
constructorArgs,
optimizerConfig,
evmVersion: undefined,
};
case VerificationOptions.ContractCode:
return {
option: verificationOption,
constructorArgs,
optimizerConfig,
};
case VerificationOptions.JsonInput:
return {
option: verificationOption,
constructorArgs,
};
default:
throw new Error("Invalid verification option for Solidity");
}
} else if (language === EvmProgrammingLanguage.Vyper) {
switch (verificationOption) {
case VerificationOptions.UploadFile:
return {
option: verificationOption,
constructorArgs,
};
case VerificationOptions.ContractCode:
return {
option: verificationOption,
constructorArgs,
};
case VerificationOptions.JsonInput:
return {
option: verificationOption,
constructorArgs,
};
default:
throw new Error("Invalid verification option for Vyper");
}
}

throw new Error("Invalid language (getVerifyFormInitialValue)");
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EvmContractVerifyForm } from "../../types";
import { Control } from "react-hook-form";
import { ConstructorArgs } from "../ConstructorArgs";
import { OptimizerConfiguration } from "../OptimizerConfiguration";

interface EvmContractVerifySolidityUploadFilesProps {
control: Control<EvmContractVerifyForm>;
Expand All @@ -15,6 +16,8 @@ export const EvmContractVerifySolidityUploadFiles = ({
<br />
<br />
<ConstructorArgs control={control} />
<br />
<OptimizerConfiguration control={control} />
</div>
);
};
15 changes: 9 additions & 6 deletions src/lib/pages/evm-contract-verify/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import { isHex20Bytes, truncate } from "lib/utils";
import { EvmContractVerifySolidity } from "./components/solidity/EvmContractVerifySolidity";
import { EvmContractVerifyVyper } from "./components/vyper/EvmContractVerifyVyper";
import { NoMobile } from "lib/components/modal";
import { getVerifyFormInitialValue } from "./components/helper";

export const EvmContractVerify = () => {
useEvmConfig({ shouldRedirect: true });
const isMobile = useMobile();
const router = useRouter();
const contractAddressQueryParam = router.query.contractAddress ?? "";
// TODO: add evm contract address
const { contract: exampleContractAddress } = useExampleAddresses();

useEffect(() => {
Expand Down Expand Up @@ -203,11 +203,14 @@ export const EvmContractVerify = () => {
setValue("verifyForm.language", selectedOption.value);
setValue("compilerVersion", "");
setValue(
"verifyForm.form.option",
selectedOption.value ===
EvmProgrammingLanguage.Solidity
? VerificationOptions.UploadFiles
: VerificationOptions.UploadFile
"verifyForm.form",
getVerifyFormInitialValue(
selectedOption.value,
selectedOption.value ===
EvmProgrammingLanguage.Solidity
? VerificationOptions.UploadFiles
: VerificationOptions.UploadFile
)
);
}}
value={programmingLangaugeOptions.find(
Expand Down
30 changes: 23 additions & 7 deletions src/lib/pages/evm-contract-verify/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ export enum VerificationOptions {
Foundry = "foundry",
}

const zOptimizerConfig = z.object({
enabled: z.boolean(),
runs: z.number().nonnegative(),
});

const zConstructorArgs = z.object({
enabled: z.boolean(),
value: z.string().refine((val) => val !== "", {
message: " ",
}),
});

const zEvmVersion = z.string().optional();

// MARK - Query Params
export const zEvmContractVerifyQueryParams = z.object({
contractAddress: zHexAddr20,
Expand All @@ -24,18 +38,20 @@ export const zEvmContractVerifyQueryParams = z.object({
// MARK - Solidity
const zEvmContractVerifySolidityOptionUploadFilesForm = z.object({
option: z.literal(VerificationOptions.UploadFiles),
constructorArgs: z.string().optional(),
evmVersion: z.string(),
constructorArgs: zConstructorArgs,
optimizerConfig: zOptimizerConfig,
evmVersion: zEvmVersion,
});

const zEvmContractVerifySolidityOptionContractCodeForm = z.object({
option: z.literal(VerificationOptions.ContractCode),
constructorArgs: z.string().optional(),
constructorArgs: zConstructorArgs,
optimizerConfig: zOptimizerConfig,
});

const zEvmContractVerifySolidityOptionJsonInputForm = z.object({
option: z.literal(VerificationOptions.JsonInput),
constructorArgs: z.string().optional(),
constructorArgs: zConstructorArgs,
});

const zEvmContractVerifySolidityOptionHardhatForm = z.object({
Expand All @@ -49,17 +65,17 @@ const zEvmContractVerifySolidityOptionFoundryForm = z.object({
// MARK - Vyper
const zEvmContractVerifyVyperOptionUploadFileForm = z.object({
option: z.literal(VerificationOptions.UploadFile),
constructorArgs: z.string().optional(),
constructorArgs: zConstructorArgs,
});

const zEvmContractVerifyVyperOptionContractCodeForm = z.object({
option: z.literal(VerificationOptions.ContractCode),
constructorArgs: z.string().optional(),
constructorArgs: zConstructorArgs,
});

const zEvmContractVerifyVyperOptionJsonInputForm = z.object({
option: z.literal(VerificationOptions.JsonInput),
constructorArgs: z.string().optional(),
constructorArgs: zConstructorArgs,
});

// MARK - Union of options by language
Expand Down
4 changes: 3 additions & 1 deletion src/lib/styles/theme/components/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ export const Input: ComponentStyleConfig = {
borderWidth: "2px",
},
_disabled: {
borderStyle: "dashed",
color: "text.disabled",
opacity: 0.8,
backgroundColor: "gray.900",
pointerEvents: "none",
},
_invalid: {
borderColor: "error.main",
Expand Down
Loading