diff --git a/apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx b/apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx index 591e38c6ccf..640b285353f 100644 --- a/apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx +++ b/apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx @@ -34,6 +34,7 @@ import { } from "thirdweb/deploys"; import { useActiveAccount, useActiveWalletChain } from "thirdweb/react"; import { upload } from "thirdweb/storage"; +import { isZkSyncChain } from "thirdweb/utils"; import { FormHelperText, FormLabel, Heading, Text } from "tw-components"; import { useCustomFactoryAbi, useFunctionParamsFromABI } from "../hooks"; import { addContractToMultiChainRegistry } from "../utils"; @@ -426,7 +427,10 @@ export const CustomContractForm: React.FC = ({ } } - if (metadata.name === "MarketplaceV3") { + if ( + metadata.name === "MarketplaceV3" && + !(await isZkSyncChain(walletChain)) + ) { // special case for marketplace return await deployMarketplaceContract({ account: activeAccount, diff --git a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts index c3e83ab0819..87d185ef3bd 100644 --- a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts +++ b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts @@ -3,7 +3,12 @@ import { describe, expect, it } from "vitest"; import { ANVIL_CHAIN } from "../../../../test/src/chains.js"; import { TEST_CLIENT } from "../../../../test/src/test-clients.js"; import { TEST_ACCOUNT_A } from "../../../../test/src/test-wallets.js"; -import { deployCloneFactory } from "./bootstrap.js"; +import { defineChain } from "../../../chains/utils.js"; +import { + deployCloneFactory, + getOrDeployInfraContract, + getOrDeployInfraForPublishedContract, +} from "./bootstrap.js"; import { getDeployedCreate2Factory } from "./create-2-factory.js"; import { getDeployedInfraContract } from "./infra.js"; @@ -42,4 +47,42 @@ describe.runIf(process.env.TW_SECRET_KEY)("bootstrap", () => { }); expect(cloneFactory).not.toBeNull(); }); + + it("should return saved implementations for zksync chains", async () => { + let infra = await getOrDeployInfraForPublishedContract({ + client: TEST_CLIENT, + chain: defineChain(300), + account: TEST_ACCOUNT_A, + contractId: "MarketplaceV3", + }); + + expect(infra.cloneFactoryContract.address).to.eq( + "0xa51baf6a9c0ef5Db8C1898d5aDD92Bf3227d6088", + ); + expect(infra.implementationContract.address).to.eq( + "0x58e0F289C7dD2025eBd0696d913ECC0fdc1CC8bc", + ); + + infra = await getOrDeployInfraForPublishedContract({ + client: TEST_CLIENT, + chain: defineChain(300), + account: TEST_ACCOUNT_A, + contractId: "DropERC721", + version: "5.0.4", + }); + + expect(infra.cloneFactoryContract.address).to.eq( + "0xa51baf6a9c0ef5Db8C1898d5aDD92Bf3227d6088", + ); + expect(infra.implementationContract.address).toBeDefined(); + + const weth = await getOrDeployInfraContract({ + client: TEST_CLIENT, + chain: defineChain(300), + account: TEST_ACCOUNT_A, + contractId: "WETH9", + }); + + expect(weth.address).to.eq("0x0462C05457Fed440740Ff3696bDd2D0577411e34"); + }); }); diff --git a/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts b/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts index 0c91c50181c..a0199c5fe37 100644 --- a/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts +++ b/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts @@ -7,6 +7,10 @@ import { isZkSyncChain } from "../../../utils/any-evm/zksync/isZkSyncChain.js"; import type { ClientAndChainAndAccount } from "../../../utils/types.js"; import { type ThirdwebContract, getContract } from "../../contract.js"; import { fetchPublishedContractMetadata } from "../publisher.js"; +import { + ZKSYNC_IMPLEMENTATIONS, + ZKSYNC_WETH, +} from "../zksync/implementations.js"; import { zkDeployCreate2Factory } from "../zksync/zkDeployCreate2Factory.js"; import { zkDeployContractDeterministic } from "../zksync/zkDeployDeterministic.js"; import { getDeployedCloneFactoryContract } from "./clone-factory.js"; @@ -69,18 +73,29 @@ export async function getOrDeployInfraForPublishedContract( publisher, version, }); - const implementationContract = await zkDeployContractDeterministic({ - chain, - client, - account, - abi: compilerMetadata.abi, - bytecode: await fetchBytecodeFromCompilerMetadata({ - compilerMetadata, - client, + + const zksyncImplementations = ZKSYNC_IMPLEMENTATIONS[chain.id]; + let implementationContract: string | undefined; + + if (zksyncImplementations) { + implementationContract = zksyncImplementations[contractId]; + } + + if (!implementationContract) { + implementationContract = await zkDeployContractDeterministic({ chain, - }), - params: constructorParams, - }); + client, + account, + abi: compilerMetadata.abi, + bytecode: await fetchBytecodeFromCompilerMetadata({ + compilerMetadata, + client, + chain, + }), + params: constructorParams, + }); + } + return { cloneFactoryContract: getContract({ address: cloneFactoryContract, @@ -188,6 +203,18 @@ export async function getOrDeployInfraContract( version?: string; }, ) { + if (options.contractId === "WETH9" && (await isZkSyncChain(options.chain))) { + const weth = ZKSYNC_WETH[options.chain.id]; + + if (weth) { + return getContract({ + client: options.client, + chain: options.chain, + address: weth, + }); + } + } + const contractMetadata = await fetchPublishedContractMetadata({ client: options.client, contractId: options.contractId, diff --git a/packages/thirdweb/src/contract/deployment/zksync/implementations.ts b/packages/thirdweb/src/contract/deployment/zksync/implementations.ts new file mode 100644 index 00000000000..3cf66ef19d0 --- /dev/null +++ b/packages/thirdweb/src/contract/deployment/zksync/implementations.ts @@ -0,0 +1,20 @@ +export const ZKSYNC_IMPLEMENTATIONS: Record> = { + [300]: { + MarketplaceV3: "0x58e0F289C7dD2025eBd0696d913ECC0fdc1CC8bc", + }, + [302]: { + MarketplaceV3: "0x8b0DBCf5b7D01eBB0F24525CE8AB72F16CE4F8C8", + }, + [324]: { + MarketplaceV3: "0xBc02441a36Bb4029Cd191b20243c2e41B862F118", + }, + [11124]: { + MarketplaceV3: "0x2dA4Dd326A6482679547071be21f74685d730504", + }, +}; + +export const ZKSYNC_WETH: Record = { + [300]: "0x0462C05457Fed440740Ff3696bDd2D0577411e34", + [324]: "0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91", + [11124]: "0x9EDCde0257F2386Ce177C3a7FCdd97787F0D841d", +}; diff --git a/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.test.ts b/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.test.ts index 1d448bc7a09..dac5601c530 100644 --- a/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.test.ts @@ -1,8 +1,12 @@ import { describe, expect, it } from "vitest"; import { CLEAN_ANVIL_CHAIN } from "../../../test/src/chains.js"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; +import { defineChain } from "../../chains/utils.js"; import { fetchPublishedContractMetadata } from "../../contract/deployment/publisher.js"; -import { getRequiredTransactions } from "./get-required-transactions.js"; +import { + getAllDefaultConstructorParamsForImplementation, + getRequiredTransactions, +} from "./get-required-transactions.js"; describe.runIf(process.env.TW_SECRET_KEY)( "getRequiredTransactions", @@ -59,5 +63,14 @@ describe.runIf(process.env.TW_SECRET_KEY)( }); expect(results.length).toBe(7); }); + + it("should return default constructor params for zksync chains", async () => { + const params = await getAllDefaultConstructorParamsForImplementation({ + chain: defineChain(300), + client: TEST_CLIENT, + }); + + expect(params.nativeTokenWrapper).toBeDefined(); + }); }, ); diff --git a/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.ts b/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.ts index 585d3d4cfe4..3b4179b45cb 100644 --- a/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.ts +++ b/packages/thirdweb/src/extensions/prebuilts/get-required-transactions.ts @@ -3,6 +3,7 @@ import type { ThirdwebClient } from "../../client/client.js"; import { getDeployedCreate2Factory } from "../../contract/deployment/utils/create-2-factory.js"; import { getDeployedInfraContract } from "../../contract/deployment/utils/infra.js"; import { getDeployedInfraContractFromMetadata } from "../../contract/deployment/utils/infra.js"; +import { ZKSYNC_WETH } from "../../contract/deployment/zksync/implementations.js"; import { computePublishedContractAddress } from "../../utils/any-evm/compute-published-contract-address.js"; import type { FetchDeployMetadataResult } from "../../utils/any-evm/deploy-metadata.js"; import { isZkSyncChain } from "../../utils/any-evm/zksync/isZkSyncChain.js"; @@ -227,8 +228,11 @@ export async function getAllDefaultConstructorParamsForImplementation(args: { const { chain, client } = args; const isZkSync = await isZkSyncChain(chain); if (isZkSync) { - // zksync contracts dont need these implementation constructor params - return {}; + const weth = ZKSYNC_WETH[chain.id]; + + return { + nativeTokenWrapper: weth, + }; } const [forwarder, weth] = await Promise.all([ computePublishedContractAddress({