Skip to content

Commit 3f83a37

Browse files
committed
New zksolc metadata format (#4568)
## Problem solved Handle new zksolc metadata format ref: ipfs://QmS6ehXYWKJEJq3LBSfG2ujKPzQQJooNE7L375zyFbpxmw <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces support for a new `zksolc` metadata format in the `thirdweb` package, enhancing the handling of zkSync contracts by updating various functions and types to accommodate the new compiler type. ### Detailed summary - Added `compilerType` option to several functions and types to support `solc` and `zksolc`. - Updated `fetchPublishedContractMetadata` and `deployPublishedContract` to utilize `compilerType`. - Enhanced `formatCompilerMetadata` to handle `zksolc` specific metadata. - Modified `fetchDeployMetadata` to validate and fetch `zksolc` metadata correctly. - Updated `CustomContractForm` to determine `compilerType` based on the active wallet chain. - Improved error handling for missing `zksolc` metadata. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 5ab3a81 commit 3f83a37

File tree

9 files changed

+93
-44
lines changed

9 files changed

+93
-44
lines changed

.changeset/gold-moons-exercise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Handle new zksolc metadata format

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
} from "thirdweb/deploys";
3838
import { useActiveAccount, useActiveWalletChain } from "thirdweb/react";
3939
import { upload } from "thirdweb/storage";
40+
import { isZkSyncChain } from "thirdweb/utils";
4041
import { FormHelperText, FormLabel, Heading, Text } from "tw-components";
4142
import { useCustomFactoryAbi, useFunctionParamsFromABI } from "../hooks";
4243
import { addContractToMultiChainRegistry } from "../utils";
@@ -385,6 +386,8 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
385386
throw new Error("no chain");
386387
}
387388

389+
const compilerType = isZkSyncChain(walletChain) ? "zksolc" : "solc";
390+
388391
let _contractURI = "";
389392

390393
if (hasContractURI && params.contractMetadata) {
@@ -449,6 +452,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
449452
deployMetadata: m,
450453
initializeParams: params.moduleData[m.name],
451454
})),
455+
compilerType,
452456
});
453457
},
454458
});

packages/thirdweb/src/contract/actions/compiler-metadata.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export type CompilerMetadata = {
1818
};
1919
licenses: string[];
2020
isPartialAbi?: boolean;
21+
zk_version?: string;
2122
};
2223

2324
/**
@@ -26,29 +27,37 @@ export type CompilerMetadata = {
2627
* @returns The formatted metadata.
2728
* @internal
2829
*/
29-
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix later
30-
export function formatCompilerMetadata(metadata: any): CompilerMetadata {
31-
const compilationTarget = metadata.settings.compilationTarget;
30+
export function formatCompilerMetadata(
31+
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix later
32+
metadata: any,
33+
compilerType?: "solc" | "zksolc",
34+
): CompilerMetadata {
35+
let meta = metadata;
36+
if (compilerType === "zksolc") {
37+
meta = metadata.source_metadata || meta;
38+
}
39+
const compilationTarget = meta.settings.compilationTarget;
3240
const targets = Object.keys(compilationTarget);
3341
const name = compilationTarget[targets[0] as keyof typeof compilationTarget];
3442
const info = {
35-
title: metadata.output.devdoc.title,
36-
author: metadata.output.devdoc.author,
37-
details: metadata.output.devdoc.detail,
38-
notice: metadata.output.userdoc.notice,
43+
title: meta.output.devdoc.title,
44+
author: meta.output.devdoc.author,
45+
details: meta.output.devdoc.detail,
46+
notice: meta.output.userdoc.notice,
3947
};
4048
const licenses: string[] = [
4149
...new Set(
4250
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix later
43-
Object.entries(metadata.sources).map(([, src]) => (src as any).license),
51+
Object.entries(meta.sources).map(([, src]) => (src as any).license),
4452
),
4553
];
4654
return {
4755
name,
48-
abi: metadata?.output?.abi || [],
49-
metadata,
56+
abi: meta?.output?.abi || [],
57+
metadata: meta,
5058
info,
5159
licenses,
52-
isPartialAbi: metadata.isPartialAbi,
60+
isPartialAbi: meta.isPartialAbi,
61+
zk_version: metadata.zk_version,
5362
};
5463
}

packages/thirdweb/src/contract/deployment/publisher.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export async function fetchPublishedContractMetadata(options: {
2424
contractId: string;
2525
publisher?: string;
2626
version?: string;
27+
compilerType?: "solc" | "zksolc";
2728
}): Promise<FetchDeployMetadataResult> {
2829
const cacheKey = `${options.contractId}-${options.publisher}-${options.version}`;
2930
return withCache(
@@ -33,6 +34,7 @@ export async function fetchPublishedContractMetadata(options: {
3334
publisherAddress: options.publisher || THIRDWEB_DEPLOYER,
3435
contractId: options.contractId,
3536
version: options.version,
37+
compilerType: options.compilerType,
3638
});
3739
if (!publishedContract.publishMetadataUri) {
3840
throw new Error(
@@ -42,6 +44,7 @@ export async function fetchPublishedContractMetadata(options: {
4244
const data = await fetchDeployMetadata({
4345
client: options.client,
4446
uri: publishedContract.publishMetadataUri,
47+
compilerType: options.compilerType,
4548
});
4649
return data;
4750
},
@@ -211,6 +214,7 @@ type FetchPublishedContractOptions = {
211214
contractId: string;
212215
version?: string;
213216
client: ThirdwebClient;
217+
compilerType?: "solc" | "zksolc";
214218
};
215219

216220
/**

packages/thirdweb/src/contract/deployment/utils/bootstrap.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export async function getOrDeployInfraForPublishedContract(
2727
constructorParams?: Record<string, unknown>;
2828
publisher?: string;
2929
version?: string;
30+
compilerType?: "solc" | "zksolc";
3031
},
3132
): Promise<{
3233
cloneFactoryContract: ThirdwebContract;
@@ -40,6 +41,7 @@ export async function getOrDeployInfraForPublishedContract(
4041
constructorParams,
4142
publisher,
4243
version,
44+
compilerType,
4345
} = args;
4446

4547
if (isZkSyncChain(chain)) {
@@ -50,9 +52,10 @@ export async function getOrDeployInfraForPublishedContract(
5052
});
5153
const compilerMetadata = await fetchPublishedContractMetadata({
5254
client,
53-
contractId: `${contractId}_ZkSync`, // different contract id for zkSync
55+
contractId,
5456
publisher,
5557
version,
58+
compilerType,
5659
});
5760
const implementationContract = await zkDeployContractDeterministic({
5861
chain,

packages/thirdweb/src/exports/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export { isEIP155Enforced } from "../utils/any-evm/is-eip155-enforced.js";
2222
export { keccakId } from "../utils/any-evm/keccak-id.js";
2323
export { getKeylessTransaction } from "../utils/any-evm/keyless-transaction.js";
2424
export type { ExtendedMetadata } from "../utils/any-evm/deploy-metadata.js";
25+
export { isZkSyncChain } from "../utils/any-evm/zksync/isZkSyncChain.js";
2526

2627
//signatures
2728
export {

packages/thirdweb/src/extensions/prebuilts/deploy-published.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type DeployPublishedContractOptions = {
3333
version?: string;
3434
implementationConstructorParams?: Record<string, unknown>;
3535
salt?: string;
36+
compilerType?: "solc" | "zksolc";
3637
};
3738

3839
/**
@@ -92,12 +93,14 @@ export async function deployPublishedContract(
9293
version,
9394
implementationConstructorParams,
9495
salt,
96+
compilerType,
9597
} = options;
9698
const deployMetadata = await fetchPublishedContractMetadata({
9799
client,
98-
contractId: isZkSyncChain(chain) ? `${contractId}_ZkSync` : contractId,
100+
contractId,
99101
publisher,
100102
version,
103+
compilerType,
101104
});
102105

103106
return deployContractfromDeployMetadata({
@@ -108,6 +111,7 @@ export async function deployPublishedContract(
108111
initializeParams: contractParams,
109112
implementationConstructorParams,
110113
salt,
114+
compilerType,
111115
});
112116
}
113117

@@ -126,6 +130,7 @@ export type DeployContractfromDeployMetadataOptions = {
126130
initializeParams?: Record<string, unknown>;
127131
}[];
128132
salt?: string;
133+
compilerType?: "solc" | "zksolc";
129134
};
130135

131136
/**
@@ -143,6 +148,7 @@ export async function deployContractfromDeployMetadata(
143148
implementationConstructorParams,
144149
modules,
145150
salt,
151+
compilerType,
146152
} = options;
147153
switch (deployMetadata?.deployType) {
148154
case "standard": {
@@ -176,6 +182,7 @@ export async function deployContractfromDeployMetadata(
176182
client,
177183
})),
178184
publisher: deployMetadata.publisher,
185+
compilerType,
179186
});
180187

181188
const initializeTransaction = await getInitializeTransaction({

packages/thirdweb/src/transaction/actions/zksync/send-eip712-transaction.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { toRlp } from "viem";
1+
import { hexToBytes, toRlp } from "viem";
22
import { eth_sendRawTransaction } from "../../../rpc/actions/eth_sendRawTransaction.js";
33
import { getRpcClient } from "../../../rpc/rpc.js";
44
import { toBigInt } from "../../../utils/bigint.js";
@@ -87,25 +87,17 @@ export async function populateEip712Transaction(
8787
options: SendEip712TransactionOptions,
8888
): Promise<EIP721TransactionSerializable> {
8989
const { account, transaction } = options;
90-
let [
91-
data,
92-
to,
93-
value,
94-
gas,
95-
maxFeePerGas,
96-
maxPriorityFeePerGas,
97-
gasPerPubdata,
98-
] = await Promise.all([
99-
encode(transaction),
100-
resolvePromisedValue(transaction.to),
101-
resolvePromisedValue(transaction.value),
102-
resolvePromisedValue(transaction.gas),
103-
resolvePromisedValue(transaction.maxFeePerGas),
104-
resolvePromisedValue(transaction.maxPriorityFeePerGas),
105-
resolvePromisedValue(transaction.eip712).then(
106-
(eip712) => eip712?.gasPerPubdata,
107-
),
108-
]);
90+
let [data, to, value, gas, maxFeePerGas, maxPriorityFeePerGas, eip712] =
91+
await Promise.all([
92+
encode(transaction),
93+
resolvePromisedValue(transaction.to),
94+
resolvePromisedValue(transaction.value),
95+
resolvePromisedValue(transaction.gas),
96+
resolvePromisedValue(transaction.maxFeePerGas),
97+
resolvePromisedValue(transaction.maxPriorityFeePerGas),
98+
resolvePromisedValue(transaction.eip712),
99+
]);
100+
let gasPerPubdata = eip712?.gasPerPubdata;
109101
if (!gas || !maxFeePerGas || !maxPriorityFeePerGas) {
110102
// fetch fees and gas
111103
const rpc = getRpcClient(transaction);
@@ -118,6 +110,15 @@ export async function populateEip712Transaction(
118110
to,
119111
data,
120112
value: value ? numberToHex(value) : undefined,
113+
gasPerPubdata,
114+
eip712Meta: {
115+
...eip712,
116+
gasPerPubdata: gasPerPubdata ? toHex(gasPerPubdata) : toHex(50000n),
117+
factoryDeps: eip712?.factoryDeps?.map((dep) =>
118+
Array.from(hexToBytes(dep)),
119+
),
120+
},
121+
type: "0x71",
121122
// biome-ignore lint/suspicious/noExplicitAny: TODO add to RPC method types
122123
} as any,
123124
],

packages/thirdweb/src/utils/any-evm/deploy-metadata.ts

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { Prettify } from "../type-utils.js";
88
type FetchDeployMetadataOptions = {
99
uri: string;
1010
client: ThirdwebClient;
11+
compilerType?: "solc" | "zksolc";
1112
};
1213

1314
export type FetchDeployMetadataResult = Partial<ExtendedMetadata> &
@@ -22,26 +23,33 @@ export type FetchDeployMetadataResult = Partial<ExtendedMetadata> &
2223
export async function fetchDeployMetadata(
2324
options: FetchDeployMetadataOptions,
2425
): Promise<FetchDeployMetadataResult> {
26+
const isZksolc = options.compilerType === "zksolc";
2527
const rawMeta: RawCompilerMetadata = await download({
2628
uri: options.uri,
2729
client: options.client,
2830
}).then((r) => r.json());
29-
// TODO: proper handling of different compiler metadata types
30-
const metadataUri =
31-
rawMeta.compilers?.zksolc?.length > 0 && rawMeta.name.endsWith("_ZkSync")
32-
? rawMeta.compilers.zksolc[0].metadataUri
33-
: rawMeta.metadataUri;
34-
const bytecodeUri =
35-
rawMeta.compilers?.zksolc?.length > 0 && rawMeta.name.endsWith("_ZkSync")
36-
? rawMeta.compilers.zksolc[0].bytecodeUri
37-
: rawMeta.bytecodeUri;
31+
32+
if (
33+
isZksolc &&
34+
(!rawMeta.compilers?.zksolc || rawMeta.compilers?.zksolc.length === 0)
35+
) {
36+
throw new Error(`No zksolc metadata found for contract: ${rawMeta.name}`);
37+
}
38+
39+
const metadataUri = isZksolc
40+
? rawMeta.compilers.zksolc[0].metadataUri
41+
: rawMeta.metadataUri;
42+
const bytecodeUri = isZksolc
43+
? rawMeta.compilers.zksolc[0].bytecodeUri
44+
: rawMeta.bytecodeUri;
3845
const [deployBytecode, parsedMeta] = await Promise.all([
3946
download({ uri: bytecodeUri, client: options.client }).then(
4047
(res) => res.text() as Promise<Hex>,
4148
),
4249
fetchAndParseCompilerMetadata({
4350
client: options.client,
4451
uri: metadataUri,
52+
compilerType: options.compilerType,
4553
}),
4654
]);
4755

@@ -66,12 +74,18 @@ async function fetchAndParseCompilerMetadata(
6674
requestTimeoutMs: CONTRACT_METADATA_TIMEOUT_SEC,
6775
})
6876
).json();
69-
if (!metadata || !metadata.output) {
77+
if (
78+
(!metadata || !metadata.output) &&
79+
(!metadata.source_metadata || !metadata.source_metadata.output)
80+
) {
7081
throw new Error(
7182
`Could not resolve metadata for contract at ${options.uri}`,
7283
);
7384
}
74-
return { ...metadata, ...formatCompilerMetadata(metadata) };
85+
return {
86+
...metadata,
87+
...formatCompilerMetadata(metadata, options.compilerType),
88+
};
7589
}
7690

7791
// types
@@ -128,6 +142,7 @@ type ParsedCompilerMetadata = {
128142
};
129143
licenses: string[];
130144
isPartialAbi?: boolean;
145+
zk_version?: string;
131146
};
132147

133148
export type CompilerMetadata = Prettify<

0 commit comments

Comments
 (0)