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

FRO-752: Verify Contract - Contract Address & Verification Method #1187

Merged
merged 10 commits into from
Jan 13, 2025
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

- [#1187](https://github.com/alleslabs/celatone-frontend/pull/1187) Add onboarding section to EVM contract details page and add EVM contract verify page
- [#1184](https://github.com/alleslabs/celatone-frontend/pull/1184) Add custom layer to Initia Widget
- [#1182](https://github.com/alleslabs/celatone-frontend/pull/1182) Add Initia Widget

Expand Down
1 change: 1 addition & 0 deletions src/lib/amplitude/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export enum AmpEvent {
TO_CONTRACT_DETAILS = "To Contract Detail",
TO_CODE_DETAILS = "To Code Detail",
TO_EVM_CONTRACT_DETAILS = "To EVM Contract Detail",
TO_EVM_CONTRACT_VERIFY = "To EVM Contract Verify",
TO_PROJECT_DETAILS = "To Public Project Detail",
TO_EVM_TRANSACTION_DETAILS = "To EVM Transaction Detail",
TO_TRANSACTION_DETAILS = "To Transaction Detail",
Expand Down
53 changes: 53 additions & 0 deletions src/lib/components/evm-verify-section/NotVerifiedDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Button, Flex, Text } from "@chakra-ui/react";

import { useInternalNavigate } from "lib/app-provider";
import type { HexAddr20 } from "lib/types";

interface NotVerifiedDetailsProps {
contractAddress: HexAddr20;
}

export const NotVerifiedDetails = ({
contractAddress,
}: NotVerifiedDetailsProps) => {
const navigate = useInternalNavigate();

const handleNavigate = () =>
navigate({
pathname: "/evm-contracts/verify",
query: { contractAddress },
});

return (
<Flex
pl={6}
justifyContent="space-between"
alignItems="center"
w="full"
borderColor="primary.main"
borderLeftWidth={4}
gap={2}
>
<Text variant="body2" color="text.dark">
This contract has not been verified. If you are the owner, you can{" "}
<Text
as="span"
cursor="pointer"
color="primary.main"
transition="all 0.25s ease-in-out"
_hover={{
textDecoration: "underline",
textDecorationColor: "primary.light",
}}
onClick={handleNavigate}
>
verify it
</Text>{" "}
to allow other users to view the source code
</Text>
<Button variant="ghost-primary" size="sm" onClick={handleNavigate}>
Verify contract
</Button>
</Flex>
);
};
1 change: 1 addition & 0 deletions src/lib/components/evm-verify-section/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./NotVerifiedDetails";
146 changes: 90 additions & 56 deletions src/lib/components/forms/SelectInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Flex, Stack, Text } from "@chakra-ui/react";
import type { SystemStyleObject } from "@chakra-ui/styled-system";
import type { Props } from "chakra-react-select";
import { Select } from "chakra-react-select";
Expand All @@ -13,7 +14,10 @@ export interface SelectInputOption<OptionValue extends SelectInputOptionValue> {
interface SelectInputProps<
OptionValue extends SelectInputOptionValue,
IsMulti extends boolean = false,
> extends Props<SelectInputOption<OptionValue>, IsMulti> {}
> extends Props<SelectInputOption<OptionValue>, IsMulti> {
label?: string;
isRequired?: boolean;
}

const handleFilterOption = (
candidate: { label: string; value: string },
Expand Down Expand Up @@ -48,60 +52,90 @@ export const SelectInput = <
onFocus,
autoFocus,
classNamePrefix,
label,
isRequired,
isDisabled,
}: SelectInputProps<OptionValue, IsMulti>) => (
<Select<SelectInputOption<OptionValue>, IsMulti>
menuPosition="fixed"
menuPortalTarget={menuPortalTarget}
placeholder={placeholder}
options={options}
value={value}
onChange={onChange}
size={size}
filterOption={handleFilterOption}
formatOptionLabel={formatOptionLabel}
components={components}
isSearchable={isSearchable}
chakraStyles={{
container: (provided: SystemStyleObject) => ({
...provided,
width: "100%",
}),
valueContainer: (provided: SystemStyleObject) => ({
...provided,
pl: 3,
pr: 0,
}),
dropdownIndicator: (provided: SystemStyleObject) => ({
...provided,
px: 2,
color: "gray.600",
}),
placeholder: (provided: SystemStyleObject) => ({
...provided,
color: "gray.500",
fontSize: "14px",
whiteSpace: "nowrap",
}),
option: (provided) => ({
...provided,
color: "text.main",
fontSize: "16px",
_hover: {
bg: "gray.700",
},
_selected: {
bg: "gray.800",
},
}),
...chakraStyles,
}}
inputId={inputId}
name={name}
isMulti={isMulti}
closeMenuOnSelect={closeMenuOnSelect}
onBlur={onBlur}
onFocus={onFocus}
autoFocus={autoFocus}
classNamePrefix={classNamePrefix}
/>
<Stack position="relative">
{label && (
<Text
className="form-label"
sx={{
fontSize: "12px",
color: "text.dark",
letterSpacing: "0.15px",
position: "absolute",
ml: 3,
px: 1,
bg: "background.main",
top: -2,
zIndex: 1,
"::after": {
content: isRequired ? '"* (Required)"' : '""',
color: "error.main",
ml: 1,
},
opacity: isDisabled ? 0.3 : 1,
}}
>
{label}
</Text>
)}
<Select<SelectInputOption<OptionValue>, IsMulti>
menuPosition="fixed"
menuPortalTarget={menuPortalTarget}
placeholder={placeholder}
options={options}
value={value}
isDisabled={isDisabled}
onChange={onChange}
size={size}
filterOption={handleFilterOption}
formatOptionLabel={formatOptionLabel}
components={components}
isSearchable={isSearchable}
chakraStyles={{
container: (provided: SystemStyleObject) => ({
...provided,
width: "100%",
}),
valueContainer: (provided: SystemStyleObject) => ({
...provided,
pl: 3,
pr: 0,
}),
dropdownIndicator: (provided: SystemStyleObject) => ({
...provided,
px: 2,
color: "gray.600",
}),
placeholder: (provided: SystemStyleObject) => ({
...provided,
color: "gray.500",
fontSize: "14px",
whiteSpace: "nowrap",
}),
option: (provided) => ({
...provided,
color: "text.main",
fontSize: "16px",
_hover: {
bg: "gray.700",
},
_selected: {
bg: "gray.800",
},
}),
...chakraStyles,
}}
inputId={inputId}
name={name}
isMulti={isMulti}
closeMenuOnSelect={closeMenuOnSelect}
onBlur={onBlur}
onFocus={onFocus}
autoFocus={autoFocus}
classNamePrefix={classNamePrefix}
/>
</Stack>
);
1 change: 1 addition & 0 deletions src/lib/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from "./useGetMaxLengthError";
export * from "./useLocalStorage";
export * from "./useUploadCode";
export * from "./useTxBroadcast";
export * from "./useStepper";
48 changes: 48 additions & 0 deletions src/lib/hooks/useStepper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useCallback, useEffect } from "react";

export const useStepper = (
total: number,
handleSubmit: () => void,
handleBack?: () => void
) => {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();

const currentStep = searchParams.get("step") ?? "1";

useEffect(() => {
if (Number(currentStep) === 1) return;
const params = new URLSearchParams(searchParams);
params.set("step", "1");
router.replace(`${pathname}?${params.toString()}`);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const handleNext = useCallback(() => {
const params = new URLSearchParams(searchParams);
params.set("step", String(Number(currentStep) + 1));

return currentStep && Number(currentStep) < total
? router.replace(`${pathname}?${params.toString()}`)
: handleSubmit();
}, [currentStep, handleSubmit, total, pathname, router, searchParams]);

const handlePrevious = useCallback(() => {
const params = new URLSearchParams(searchParams);
params.set("step", String(Number(currentStep) - 1));

return currentStep && Number(currentStep) > 1
? router.replace(`${pathname}?${params.toString()}`)
: (handleBack?.() ?? router.back());
}, [currentStep, pathname, router, searchParams, handleBack]);

return {
currentStepIndex: Number(currentStep) - 1,
handleNext,
handlePrevious,
hasNext: Number(currentStep) < total,
hasPrevious: Number(currentStep) > 1,
};
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Flex, Text } from "@chakra-ui/react";

import { getStepStyles } from "../hooks/utils";
import { getStepStyles } from "../helpers";

const steps = [
{ label: "Network Details" },
Expand Down
58 changes: 0 additions & 58 deletions src/lib/pages/custom-network/manual/hooks/useNetworkStepper.ts

This file was deleted.

13 changes: 10 additions & 3 deletions src/lib/pages/custom-network/manual/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ import {
zWalletRegistryForm,
} from "../types";
import type { AddNetworkManualForm } from "../types";
import { useAllowCustomNetworks, useChainConfigs } from "lib/app-provider";
import {
useAllowCustomNetworks,
useChainConfigs,
useInternalNavigate,
} from "lib/app-provider";
import ActionPageContainer from "lib/components/ActionPageContainer";
import { CustomIcon } from "lib/components/icon";
import { FooterCta } from "lib/components/layouts";
import { CelatoneSeo } from "lib/components/Seo";
import { useLocalChainConfigStore } from "lib/providers/store";

import { AddNetworkForm, AddNetworkStepper } from "./components";
import { useNetworkStepper } from "./hooks/useNetworkStepper";
import { useStepper } from "lib/hooks";

export const AddNetworkManual = () => {
useAllowCustomNetworks({ shouldRedirect: true });
const navigate = useInternalNavigate();
const { isOpen, onClose, onOpen } = useDisclosure();
const { addLocalChainConfig } = useLocalChainConfigStore();
const { isChainIdExist } = useChainConfigs();
Expand Down Expand Up @@ -95,7 +100,9 @@ export const AddNetworkManual = () => {
};

const { currentStepIndex, handleNext, handlePrevious, hasNext, hasPrevious } =
useNetworkStepper(3, handleSubmit(handleSubmitForm));
useStepper(3, handleSubmit(handleSubmitForm), () =>
navigate({ pathname: "/custom-network/add" })
);

const isFormDisabled = () => {
if (currentStepIndex === 0)
Expand Down
Loading
Loading