Skip to content

Commit d9fb544

Browse files
committed
[Dashboard | SDK] Feature: Ref values for address params in publish (#5360)
PROT-932 PROT-864 ## Problem solved https://linear.app/thirdweb/project/[contract-tooling]-deployment-publish-flow-revamp-0194e04e2a84/overview Handle contract refs in publish form -- Resolve / deploy all linked contracts in publish metadata, and pass the addresses as constructor args for corresponding params. It recursively deploys all referenced contracts through the ref chain, before deploying the main contract. <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on enhancing the contract deployment and parameter handling in the thirdweb platform, introducing dynamic parameters, improved UI components, and better error handling for contract interactions. ### Detailed summary - Updated `deploy-with-abi.ts` to return the contract address instead of throwing an error if already deployed. - Enhanced UI components in `string-input.tsx` and `raw-input.tsx` for better user experience. - Added dynamic parameter handling in multiple components. - Introduced new types for dynamic parameters in `deploy-metadata.ts`. - Improved form handling in `FormFieldSetup` and related components. - Added reference contract input fields in various components for dynamic contract deployments. - Enhanced error handling and validation in the deployment forms. - Updated component structure for better maintainability and clarity. > The following files were skipped due to too many changes: `apps/dashboard/src/components/contract-components/contract-publish-form/contract-params-fieldset.tsx` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent b49dde3 commit d9fb544

File tree

25 files changed

+2136
-311
lines changed

25 files changed

+2136
-311
lines changed

apps/dashboard/src/@/components/blocks/FormFieldSetup.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ import { ToolTipLabel } from "@/components/ui/tooltip";
33
import { AsteriskIcon, InfoIcon } from "lucide-react";
44

55
export function FormFieldSetup(props: {
6-
htmlFor: string;
6+
htmlFor?: string;
77
label: string;
88
errorMessage: React.ReactNode | undefined;
99
children: React.ReactNode;
1010
tooltip?: React.ReactNode;
1111
isRequired: boolean;
1212
helperText?: React.ReactNode;
13+
className?: string;
1314
}) {
1415
return (
15-
<div>
16+
<div className={props.className}>
1617
<div className="mb-2 inline-flex items-center gap-1">
1718
<Label htmlFor={props.htmlFor}>{props.label}</Label>
1819

apps/dashboard/src/app/(dashboard)/contracts/publish/[publish_uri]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export default async function PublishContractPage(
7373
}
7474

7575
return (
76-
<div className="container flex flex-col gap-8 py-8">
76+
<div className="container flex max-w-[1130px] flex-col gap-8 py-8">
7777
<ChakraProviderSetup>
7878
<ContractPublishForm
7979
jwt={token}

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

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ type CustomContractDeploymentFormData = {
6969
deployDeterministic: boolean;
7070
saltForCreate2: string;
7171
signerAsSalt: boolean;
72-
deployParams: Record<string, string>;
72+
deployParams: Record<string, string | DynamicValue>;
7373
moduleData: Record<string, Record<string, string>>;
7474
contractMetadata?: {
7575
name: string;
@@ -80,6 +80,18 @@ type CustomContractDeploymentFormData = {
8080
recipients?: Recipient[];
8181
};
8282

83+
export interface DynamicValue {
84+
dynamicValue: {
85+
type: string;
86+
refContracts?: {
87+
publisherAddress: string;
88+
version: string;
89+
contractId: string;
90+
salt?: string;
91+
}[];
92+
};
93+
}
94+
8395
export type CustomContractDeploymentForm =
8496
UseFormReturn<CustomContractDeploymentFormData>;
8597

@@ -159,6 +171,8 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
159171
"initialize",
160172
);
161173

174+
const implementationConstructorParams = metadata?.implConstructorParams;
175+
162176
const isFactoryDeployment =
163177
metadata?.isDeployableViaFactory ||
164178
metadata?.isDeployableViaProxy ||
@@ -206,9 +220,16 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
206220
acc[param.name] = activeAccount.address;
207221
}
208222

223+
// specify refs if present
224+
const dynamicValue =
225+
metadata?.constructorParams?.[param.name]?.dynamicValue;
226+
if (dynamicValue && acc[param.name] === "") {
227+
acc[param.name] = { dynamicValue };
228+
}
229+
209230
return acc;
210231
},
211-
{} as Record<string, string>,
232+
{} as Record<string, string | DynamicValue>,
212233
),
213234
}),
214235
[deployParams, metadata?.constructorParams, activeAccount, walletChain?.id],
@@ -353,7 +374,11 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
353374
const contructorParams = metadata?.constructorParams || {};
354375
const extraMetadataParam = contructorParams[paramKey];
355376

356-
if (shouldHide(paramKey) || !extraMetadataParam?.hidden) {
377+
if (
378+
shouldHide(paramKey) ||
379+
extraMetadataParam?.hidden !== true ||
380+
extraMetadataParam?.dynamicValue
381+
) {
357382
return null;
358383
}
359384

@@ -412,11 +437,12 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
412437
params: {
413438
name: params.contractMetadata?.name || "",
414439
contractURI: _contractURI,
415-
defaultAdmin: params.deployParams._defaultAdmin,
440+
defaultAdmin: params.deployParams._defaultAdmin as string,
416441
platformFeeBps: Number(params.deployParams._platformFeeBps),
417-
platformFeeRecipient: params.deployParams._platformFeeRecipient,
442+
platformFeeRecipient: params.deployParams
443+
._platformFeeRecipient as string,
418444
trustedForwarders: params.deployParams._trustedForwarders
419-
? JSON.parse(params.deployParams._trustedForwarders)
445+
? JSON.parse(params.deployParams._trustedForwarders as string)
420446
: undefined,
421447
},
422448
});
@@ -442,6 +468,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
442468
client: thirdwebClient,
443469
deployMetadata: metadata,
444470
initializeParams,
471+
implementationConstructorParams,
445472
salt,
446473
modules: modules?.map((m) => ({
447474
deployMetadata: m,
@@ -652,7 +679,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
652679
).error?.message,
653680
}}
654681
royaltyBps={{
655-
value: form.watch("deployParams._royaltyBps"),
682+
value: form.watch("deployParams._royaltyBps") as string,
656683
isInvalid: !!form.getFieldState(
657684
"deployParams._royaltyBps",
658685
form.formState,
@@ -749,7 +776,11 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
749776
const contructorParams = metadata?.constructorParams || {};
750777
const extraMetadataParam = contructorParams[paramKey];
751778

752-
if (shouldHide(paramKey) || extraMetadataParam?.hidden) {
779+
if (
780+
shouldHide(paramKey) ||
781+
extraMetadataParam?.hidden === true ||
782+
extraMetadataParam?.dynamicValue
783+
) {
753784
return null;
754785
}
755786

apps/dashboard/src/components/contract-components/contract-deploy-form/trusted-forwarders-fieldset.tsx

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { Flex, FormControl, InputGroup } from "@chakra-ui/react";
22
import { SolidityInput } from "contract-ui/components/solidity-inputs";
33
import { FormErrorMessage, FormHelperText, FormLabel } from "tw-components";
44
import { Fieldset } from "./common";
5-
import type { CustomContractDeploymentForm } from "./custom-contract";
5+
import type {
6+
CustomContractDeploymentForm,
7+
DynamicValue,
8+
} from "./custom-contract";
69

710
interface TrustedForwardersFieldsetProps {
811
form: CustomContractDeploymentForm;
@@ -11,56 +14,65 @@ interface TrustedForwardersFieldsetProps {
1114
export const TrustedForwardersFieldset: React.FC<
1215
TrustedForwardersFieldsetProps
1316
> = ({ form }) => {
17+
const isDynamicValue = (val: string | DynamicValue): val is DynamicValue => {
18+
return typeof val === "object" && val !== null && "dynamicValue" in val;
19+
};
20+
21+
const value = form.watch("deployParams._trustedForwarders");
1422
return (
15-
<Fieldset legend="Gasless">
16-
<FormControl
17-
isRequired
18-
isInvalid={
19-
!!form.getFieldState(
20-
"deployParams._trustedForwarders",
21-
form.formState,
22-
).error
23-
}
24-
>
25-
<div className="flex items-center justify-between gap-6">
26-
{/* left */}
27-
<div>
28-
<FormLabel>Trusted Forwarders</FormLabel>
23+
<>
24+
{!isDynamicValue(value) && (
25+
<Fieldset legend="Gasless">
26+
<FormControl
27+
isRequired
28+
isInvalid={
29+
!!form.getFieldState(
30+
"deployParams._trustedForwarders",
31+
form.formState,
32+
).error
33+
}
34+
>
35+
<div className="flex items-center justify-between gap-6">
36+
{/* left */}
37+
<div>
38+
<FormLabel>Trusted Forwarders</FormLabel>
2939

30-
<FormHelperText className="!text-sm text-muted-foreground">
31-
<span className="mb-1 block text-muted-foreground text-sm">
32-
Trusted forwarder addresses to enable ERC-2771 transactions
33-
(i.e. gasless).
34-
</span>
40+
<FormHelperText className="!text-sm text-muted-foreground">
41+
<span className="mb-1 block text-muted-foreground text-sm">
42+
Trusted forwarder addresses to enable ERC-2771 transactions
43+
(i.e. gasless).
44+
</span>
3545

36-
<span className="block text-muted-foreground text-sm">
37-
You can provide your own forwarder.
38-
</span>
39-
</FormHelperText>
40-
</div>
41-
</div>
46+
<span className="block text-muted-foreground text-sm">
47+
You can provide your own forwarder.
48+
</span>
49+
</FormHelperText>
50+
</div>
51+
</div>
4252

43-
<div className="fade-in-0 block animate-in pt-3 duration-400">
44-
<InputGroup size="md">
45-
<Flex flexDir="column" w="full">
46-
<SolidityInput
47-
value={form.watch("deployParams._trustedForwarders")}
48-
solidityType="address[]"
49-
{...form.register("deployParams._trustedForwarders")}
50-
/>
51-
</Flex>
52-
</InputGroup>
53+
<div className="fade-in-0 block animate-in pt-3 duration-400">
54+
<InputGroup size="md">
55+
<Flex flexDir="column" w="full">
56+
<SolidityInput
57+
value={value}
58+
solidityType="address[]"
59+
{...form.register("deployParams._trustedForwarders")}
60+
/>
61+
</Flex>
62+
</InputGroup>
5363

54-
<FormErrorMessage>
55-
{
56-
form.getFieldState(
57-
"deployParams._trustedForwarders",
58-
form.formState,
59-
).error?.message
60-
}
61-
</FormErrorMessage>
62-
</div>
63-
</FormControl>
64-
</Fieldset>
64+
<FormErrorMessage>
65+
{
66+
form.getFieldState(
67+
"deployParams._trustedForwarders",
68+
form.formState,
69+
).error?.message
70+
}
71+
</FormErrorMessage>
72+
</div>
73+
</FormControl>
74+
</Fieldset>
75+
)}
76+
</>
6577
);
6678
};

0 commit comments

Comments
 (0)