Skip to content

Commit 8aaaae4

Browse files
committed
handle arbitrary bytes with refs
1 parent cd7f779 commit 8aaaae4

File tree

14 files changed

+673
-52
lines changed

14 files changed

+673
-52
lines changed

apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ interface DynamicValue {
8787
publisherAddress: string;
8888
version: string;
8989
contractId: string;
90+
salt?: string;
9091
}[];
9192
};
9293
}

apps/dashboard/src/components/contract-components/contract-publish-form/contract-params-fieldset.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
Heading,
2626
Text,
2727
} from "tw-components";
28-
import { RefInputFieldset } from "./ref-input-fieldset";
28+
import { DecodedInputArrayFieldset } from "./decoded-bytes-input/decoded-input-array-fieldset";
29+
import { RefInputFieldset } from "./ref-contract-input/ref-input-fieldset";
2930

3031
interface ContractParamsFieldsetProps {
3132
deployParams: readonly AbiParameter[];
@@ -175,8 +176,11 @@ export const ContractParamsFieldset: React.FC<ContractParamsFieldsetProps> = ({
175176
)}
176177
/>
177178
</>
178-
) : (
179+
) : param.type === "address" ||
180+
param.type === "address[]" ? (
179181
<RefInputFieldset param={param} />
182+
) : (
183+
<DecodedInputArrayFieldset param={param} />
180184
)}
181185

182186
{(param.type === "address" ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Box, Flex, Icon } from "@chakra-ui/react";
2+
import type { AbiParameter } from "abitype";
3+
import { PlusIcon } from "lucide-react";
4+
import { useFieldArray, useFormContext } from "react-hook-form";
5+
import { Button, Text } from "tw-components";
6+
import { DecodedInputSet } from "./decoded-input-set";
7+
8+
interface DecodedInputArrayFieldsetProps {
9+
param: AbiParameter;
10+
}
11+
12+
export const DecodedInputArrayFieldset: React.FC<
13+
DecodedInputArrayFieldsetProps
14+
> = ({ param }) => {
15+
const form = useFormContext();
16+
17+
const { fields, append, remove } = useFieldArray({
18+
name: `constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes`,
19+
control: form.control,
20+
});
21+
22+
return (
23+
<Flex gap={8} direction="column" as="fieldset">
24+
<Flex gap={2} direction="column">
25+
<Text>Set decoded values for this bytes param.</Text>
26+
</Flex>
27+
<Flex flexDir="column" gap={4}>
28+
{fields.map((item, index) => (
29+
<DecodedInputSet
30+
key={item.id}
31+
removeSet={remove}
32+
setIndex={index}
33+
param={param}
34+
/>
35+
))}
36+
<Box>
37+
<Button
38+
type="button"
39+
size="sm"
40+
colorScheme="primary"
41+
borderRadius="md"
42+
leftIcon={<Icon as={PlusIcon} />}
43+
isDisabled={param.type === "bytes" && fields.length >= 1}
44+
onClick={() =>
45+
append({
46+
contractId: "",
47+
version: "",
48+
publisherAddress: "",
49+
})
50+
}
51+
>
52+
New param set
53+
</Button>
54+
</Box>
55+
</Flex>
56+
</Flex>
57+
);
58+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { Box, Flex, Icon, IconButton } from "@chakra-ui/react";
2+
import type { AbiParameter } from "abitype";
3+
import { PlusIcon, TrashIcon } from "lucide-react";
4+
import { useFieldArray, useFormContext } from "react-hook-form";
5+
import { Button } from "tw-components";
6+
import { DecodedInput } from "./decoded-input";
7+
8+
interface DecodedInputSetProps {
9+
param: AbiParameter;
10+
setIndex: number;
11+
removeSet: (index: number) => void;
12+
}
13+
14+
export const DecodedInputSet: React.FC<DecodedInputSetProps> = ({
15+
param,
16+
setIndex,
17+
removeSet,
18+
}) => {
19+
const form = useFormContext();
20+
21+
const { fields, append, remove } = useFieldArray({
22+
name: `constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}`,
23+
control: form.control,
24+
});
25+
26+
return (
27+
<Flex gap={8} direction="column" as="fieldset">
28+
<Flex flexDir="column" gap={4}>
29+
{fields.map((item, index) => (
30+
<DecodedInput
31+
key={item.id}
32+
removeParam={remove}
33+
paramIndex={index}
34+
setIndex={setIndex}
35+
param={param}
36+
/>
37+
))}
38+
<Box>
39+
<Button
40+
type="button"
41+
size="sm"
42+
colorScheme="primary"
43+
borderRadius="md"
44+
leftIcon={<Icon as={PlusIcon} />}
45+
isDisabled={param.type === "bytes" && fields.length >= 1}
46+
onClick={() =>
47+
append({
48+
type: "",
49+
defaultValue: "",
50+
})
51+
}
52+
>
53+
Add param
54+
</Button>
55+
</Box>
56+
</Flex>
57+
<IconButton
58+
icon={<Icon as={TrashIcon} boxSize={5} />}
59+
aria-label="Remove set"
60+
onClick={() => removeSet(setIndex)}
61+
alignSelf="end"
62+
/>
63+
</Flex>
64+
);
65+
};
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import {
2+
Checkbox,
3+
Divider,
4+
Flex,
5+
FormControl,
6+
Icon,
7+
IconButton,
8+
Input,
9+
Select,
10+
} from "@chakra-ui/react";
11+
import type { AbiParameter } from "abitype";
12+
import { TrashIcon } from "lucide-react";
13+
import { useState } from "react";
14+
import { useFormContext } from "react-hook-form";
15+
import {} from "../../hooks";
16+
import { RefBytesInputFieldset } from "./ref-bytes-input-fieldset";
17+
18+
interface DecodedInputProps {
19+
param: AbiParameter;
20+
paramIndex: number;
21+
setIndex: number;
22+
removeParam: (index: number) => void;
23+
}
24+
25+
export const DecodedInput: React.FC<DecodedInputProps> = ({
26+
param,
27+
paramIndex,
28+
setIndex,
29+
removeParam,
30+
}) => {
31+
const form = useFormContext();
32+
const [isCustomAddress, setIsCustomAddress] = useState(false);
33+
const selectedType = form.watch(
34+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.type`,
35+
);
36+
37+
// Toggle function to handle custom input visibility and reset fields
38+
const handleToggleCustomInput = () => {
39+
setIsCustomAddress(() => {
40+
const updated = !isCustomAddress;
41+
42+
const path = `constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}`;
43+
if (!updated) {
44+
form.setValue(`${path}.dynamicValue.type`, "address");
45+
form.resetField(`${path}.defaultValue`);
46+
} else {
47+
form.setValue(`${path}.dynamicValue.type`, "");
48+
form.resetField(`${path}.dynamicValue`);
49+
}
50+
51+
return updated;
52+
});
53+
};
54+
55+
return (
56+
<Flex flexDir="column" gap={2}>
57+
<Flex
58+
w="full"
59+
gap={{ base: 4, md: 2 }}
60+
flexDir={{ base: "column", md: "row" }}
61+
>
62+
<FormControl
63+
as={Flex}
64+
flexDir="column"
65+
gap={1}
66+
isInvalid={
67+
!!form.getFieldState(
68+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.type`,
69+
form.formState,
70+
).error
71+
}
72+
>
73+
{/* <Input
74+
placeholder="param type"
75+
{...form.register(
76+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.refContracts.${index}.publisherAddress`,
77+
)}
78+
/> */}
79+
<Select
80+
placeholder="Select type"
81+
{...form.register(
82+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.type`,
83+
)}
84+
>
85+
<option value="uint256">uint256</option>
86+
<option value="address">address</option>
87+
<option value="bytes32">bytes32</option>
88+
<option value="bool">bool</option>
89+
</Select>
90+
</FormControl>
91+
{/* <FormControl as={Flex} flexDir="column" gap={1}>
92+
<Input
93+
placeholder="Enter value"
94+
{...form.register(
95+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.defaultValue`,
96+
)}
97+
/>
98+
</FormControl> */}
99+
100+
<FormControl as={Flex} flexDir="column" gap={1}>
101+
{isCustomAddress ? (
102+
<RefBytesInputFieldset
103+
param={param}
104+
setIndex={setIndex}
105+
paramIndex={paramIndex}
106+
/>
107+
) : (
108+
<Input
109+
placeholder="Enter value"
110+
{...form.register(
111+
`constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.defaultValue`,
112+
)}
113+
isDisabled={selectedType === "address" && isCustomAddress}
114+
/>
115+
)}
116+
</FormControl>
117+
<IconButton
118+
icon={<Icon as={TrashIcon} boxSize={5} />}
119+
aria-label="Remove row"
120+
onClick={() => removeParam(paramIndex)}
121+
alignSelf="end"
122+
/>
123+
</Flex>
124+
125+
{(selectedType === "address" || selectedType === "address[]") && (
126+
<Checkbox
127+
isChecked={isCustomAddress}
128+
onChange={() => handleToggleCustomInput()}
129+
>
130+
Use Dynamic Input
131+
</Checkbox>
132+
)}
133+
<Divider />
134+
</Flex>
135+
);
136+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { Box, Flex, Icon } from "@chakra-ui/react";
2+
import type { AbiParameter } from "abitype";
3+
import { PlusIcon } from "lucide-react";
4+
import { useFieldArray, useFormContext } from "react-hook-form";
5+
import { Button, Text } from "tw-components";
6+
import { RefBytesContractInput } from "./ref-bytes-input";
7+
8+
interface RefBytesInputFieldsetProps {
9+
param: AbiParameter;
10+
paramIndex: number;
11+
setIndex: number;
12+
}
13+
14+
export const RefBytesInputFieldset: React.FC<RefBytesInputFieldsetProps> = ({
15+
param,
16+
setIndex,
17+
paramIndex,
18+
}) => {
19+
const form = useFormContext();
20+
21+
const { fields, append, remove } = useFieldArray({
22+
name: `constructorParams.${param.name ? param.name : "*"}.dynamicValue.decodedBytes.${setIndex}.${paramIndex}.dynamicValue.refContracts`,
23+
control: form.control,
24+
});
25+
26+
return (
27+
<Flex gap={8} direction="column" as="fieldset">
28+
<Flex gap={2} direction="column">
29+
<Text>Set ref contract for this param.</Text>
30+
</Flex>
31+
<Flex flexDir="column" gap={4}>
32+
{fields.map((item, index) => (
33+
<RefBytesContractInput
34+
key={item.id}
35+
remove={remove}
36+
index={index}
37+
param={param}
38+
paramIndex={paramIndex}
39+
setIndex={setIndex}
40+
/>
41+
))}
42+
<Box>
43+
<Button
44+
type="button"
45+
size="sm"
46+
colorScheme="primary"
47+
borderRadius="md"
48+
leftIcon={<Icon as={PlusIcon} />}
49+
isDisabled={param.type === "address" && fields.length >= 1}
50+
onClick={() =>
51+
append({
52+
contractId: "",
53+
version: "",
54+
publisherAddress: "",
55+
salt: "",
56+
})
57+
}
58+
>
59+
Add Ref
60+
</Button>
61+
</Box>
62+
</Flex>
63+
</Flex>
64+
);
65+
};

0 commit comments

Comments
 (0)