From ef3ca89c45998a01ba83cc27eac0446f737af000 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 12 Dec 2024 00:33:46 +0530 Subject: [PATCH 1/3] Compute addresses with ref contracts --- .../prebuilts/compute-ref-deployments.ts | 156 ++++++++++++++++++ .../compute-published-contract-deploy-info.ts | 18 +- 2 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts diff --git a/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts b/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts new file mode 100644 index 00000000000..ffaef1936b4 --- /dev/null +++ b/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts @@ -0,0 +1,156 @@ +import type { Chain } from "../../chains/types.js"; +import type { ThirdwebClient } from "../../client/client.js"; +import { encodeAbiParameters } from "../../utils/abi/encodeAbiParameters.js"; +import { computePublishedContractAddress } from "../../utils/any-evm/compute-published-contract-address.js"; +import type { ImplementationConstructorParam } from "./process-ref-deployments.js"; + +type ComputeRefDeploymentsOptions = { + client: ThirdwebClient; + chain: Chain; + paramValue: string | ImplementationConstructorParam; +}; + +export async function computeRefDeployments( + options: ComputeRefDeploymentsOptions, +): Promise { + const { client, chain, paramValue } = options; + + if (typeof paramValue === "object") { + if ( + "defaultValue" in paramValue && + paramValue.defaultValue && + paramValue.defaultValue.length > 0 + ) { + return paramValue.defaultValue; + } + + if ("dynamicValue" in paramValue && paramValue.dynamicValue) { + const dynamicValue = paramValue.dynamicValue; + const contracts = dynamicValue.refContracts; + + if (dynamicValue.type === "address") { + if (!contracts || contracts.length === 0 || !contracts[0]?.contractId) { + throw new Error("Invalid or empty param value"); + } + const salt = + contracts[0]?.salt && contracts[0]?.salt.length > 0 + ? contracts[0]?.salt + : "thirdweb"; + + const addr = await computePublishedContractAddress({ + client, + chain, + contractId: contracts[0]?.contractId, + publisher: contracts[0]?.publisherAddress, + version: contracts[0]?.version, + salt, + }); + + return addr; + } + + if (dynamicValue.type === "address[]") { + if (!contracts || contracts.length === 0) { + throw new Error("Invalid or empty param value"); + } + const addressArray: string[] = []; + + for (const c of contracts) { + const salt = c?.salt && c?.salt.length > 0 ? c?.salt : "thirdweb"; + + addressArray.push( + await computePublishedContractAddress({ + client, + chain, + contractId: c.contractId, + publisher: c.publisherAddress, + version: c.version, + salt, + }), + ); + } + + return addressArray; + } + + if (dynamicValue.type === "bytes") { + if (!dynamicValue.paramsToEncode) { + throw new Error("Invalid or empty param value"); + } + const paramsToEncode = dynamicValue.paramsToEncode[0]; + + if (paramsToEncode) { + const types: string[] = []; + const values: (string | string[])[] = []; + for (const v of paramsToEncode) { + types.push(v.type); + + if (v.defaultValue) { + values.push(v.defaultValue); + } else if (v.dynamicValue) { + values.push( + await computeRefDeployments({ + client, + chain, + paramValue: v, + }), + ); + } + } + + return encodeAbiParameters( + types.map((t) => { + return { type: t }; + }), + values, + ); + } + } + + if (dynamicValue.type === "bytes[]") { + if (!dynamicValue.paramsToEncode) { + throw new Error("Invalid or empty param value"); + } + const bytesArray: string[] = []; + const paramArray = dynamicValue.paramsToEncode; + + for (const a of paramArray) { + const paramsToEncode = a; + + if (paramsToEncode) { + const types: string[] = []; + const values: (string | string[])[] = []; + for (const v of paramsToEncode) { + types.push(v.type); + + if (v.defaultValue) { + values.push(v.defaultValue); + } else if (v.dynamicValue) { + values.push( + await computeRefDeployments({ + client, + chain, + paramValue: v, + }), + ); + } + } + + bytesArray.push( + encodeAbiParameters( + types.map((t) => { + return { type: t }; + }), + values, + ), + ); + } + } + + return bytesArray; + } + } + } + + return paramValue as string; +} diff --git a/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts b/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts index 77203b08371..d8dfb3d6330 100644 --- a/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts +++ b/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts @@ -3,6 +3,8 @@ import type { Chain } from "../../chains/types.js"; import type { ThirdwebClient } from "../../client/client.js"; import { fetchPublishedContractMetadata } from "../../contract/deployment/publisher.js"; import { computeCreate2FactoryAddress } from "../../contract/deployment/utils/create-2-factory.js"; +import { computeRefDeployments } from "../../extensions/prebuilts/compute-ref-deployments.js"; +import type { ImplementationConstructorParam } from "../../extensions/prebuilts/process-ref-deployments.js"; import { encodeAbiParameters } from "../abi/encodeAbiParameters.js"; import { normalizeFunctionParams } from "../abi/normalizeFunctionParams.js"; import { ensureBytecodePrefix } from "../bytecode/prefix.js"; @@ -51,6 +53,20 @@ export async function computeDeploymentInfoFromMetadata(args: { constructorParams?: Record; salt?: string; }) { + const { client, chain, constructorParams, contractMetadata } = args; + const definedConstructorParams = + constructorParams || contractMetadata.constructorParams; + const processedConstructorParams: Record = {}; + for (const key in definedConstructorParams) { + processedConstructorParams[key] = await computeRefDeployments({ + client, + chain, + paramValue: definedConstructorParams[key] as + | string + | ImplementationConstructorParam, + }); + } + return computeDeploymentInfoFromBytecode({ client: args.client, chain: args.chain, @@ -60,7 +76,7 @@ export async function computeDeploymentInfoFromMetadata(args: { client: args.client, chain: args.chain, }), - constructorParams: args.constructorParams, + constructorParams: processedConstructorParams, salt: args.salt, }); } From 06f1f4fa6a7a68da3ab2f8ebb2f52087266f3778 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 12 Dec 2024 00:37:04 +0530 Subject: [PATCH 2/3] changeset --- .changeset/fresh-gorillas-sip.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fresh-gorillas-sip.md diff --git a/.changeset/fresh-gorillas-sip.md b/.changeset/fresh-gorillas-sip.md new file mode 100644 index 00000000000..b61dcc77a7e --- /dev/null +++ b/.changeset/fresh-gorillas-sip.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Compute addresses with ref contracts From f1a5555f42e421af38cf96ff09e3aa97b92bd371 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 19 Dec 2024 22:44:12 +0530 Subject: [PATCH 3/3] comments --- .../src/extensions/prebuilts/compute-ref-deployments.ts | 5 +++++ .../src/extensions/prebuilts/process-ref-deployments.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts b/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts index ffaef1936b4..7a3c544c7ed 100644 --- a/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts +++ b/packages/thirdweb/src/extensions/prebuilts/compute-ref-deployments.ts @@ -10,6 +10,11 @@ type ComputeRefDeploymentsOptions = { paramValue: string | ImplementationConstructorParam; }; +/** + * Computes addresses for published contract references in constructor params. + * @returns Param value after processing references. + * @internal + */ export async function computeRefDeployments( options: ComputeRefDeploymentsOptions, ): Promise { diff --git a/packages/thirdweb/src/extensions/prebuilts/process-ref-deployments.ts b/packages/thirdweb/src/extensions/prebuilts/process-ref-deployments.ts index 673ba418bb3..31d1ba898c5 100644 --- a/packages/thirdweb/src/extensions/prebuilts/process-ref-deployments.ts +++ b/packages/thirdweb/src/extensions/prebuilts/process-ref-deployments.ts @@ -17,6 +17,11 @@ type ProcessRefDeploymentsOptions = { paramValue: string | ImplementationConstructorParam; }; +/** + * Processes published contract references in constructor params. Deploys recursively if needed. + * @returns Param value after processing references. + * @internal + */ export async function processRefDeployments( options: ProcessRefDeploymentsOptions, ): Promise {