Skip to content

Commit f01de73

Browse files
feat: Support ERC-6492 signature verification on zksync chains (#5440)
1 parent a00233d commit f01de73

File tree

3 files changed

+45
-18
lines changed

3 files changed

+45
-18
lines changed

.changeset/gentle-kids-serve.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+
Support erc6492 signature verification on zksync

packages/thirdweb/src/auth/verify-hash.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { equalBytes } from "@noble/curves/abstract/utils";
21
import {
32
type Signature,
43
encodeDeployData,
4+
encodeFunctionData,
5+
isErc6492Signature,
56
serializeSignature,
67
universalSignatureValidatorAbi,
78
universalSignatureValidatorByteCode,
@@ -12,10 +13,9 @@ import { type ThirdwebContract, getContract } from "../contract/contract.js";
1213
import { isValidSignature } from "../extensions/erc1271/__generated__/isValidSignature/read/isValidSignature.js";
1314
import { eth_call } from "../rpc/actions/eth_call.js";
1415
import { getRpcClient } from "../rpc/rpc.js";
16+
import { isZkSyncChain } from "../utils/any-evm/zksync/isZkSyncChain.js";
1517
import { fromBytes } from "../utils/encoding/from-bytes.js";
16-
import { type Hex, isHex } from "../utils/encoding/hex.js";
17-
import { toBytes } from "../utils/encoding/to-bytes.js";
18-
import { isErc6492Signature } from "./is-erc6492-signature.js";
18+
import { type Hex, hexToBool, isHex } from "../utils/encoding/hex.js";
1919
import { serializeErc6492Signature } from "./serialize-erc6492-signature.js";
2020

2121
export type VerifyHashParams = {
@@ -30,6 +30,8 @@ export type VerifyHashParams = {
3030
};
3131
};
3232

33+
const ZKSYNC_VALIDATOR_ADDRESS = "0xfB688330379976DA81eB64Fe4BF50d7401763B9C";
34+
3335
/**
3436
* @description Verify that an address created the provided signature for a given hash using [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492). This function is interoperable with all wallet types, including EOAs.
3537
* This function should rarely be used directly, instead use @see {import("./verify-signature.js")} and @see {import("./verify-typed-data.js")}}
@@ -77,7 +79,7 @@ export async function verifyHash({
7779
);
7880
})();
7981

80-
const wrappedSignature = await (async () => {
82+
const wrappedSignature: Hex = await (async () => {
8183
// If no factory is provided, we have to assume its already deployed or is an EOA
8284
// TODO: Figure out how to automatically tell if our default factory was used
8385
if (!accountFactory) return signatureHex;
@@ -93,24 +95,40 @@ export async function verifyHash({
9395
});
9496
})();
9597

96-
const verificationData = encodeDeployData({
97-
abi: universalSignatureValidatorAbi,
98-
args: [address, hash, wrappedSignature],
99-
bytecode: universalSignatureValidatorByteCode,
100-
});
98+
let verificationData: {
99+
to?: string;
100+
data: Hex;
101+
};
102+
const zkSyncChain = await isZkSyncChain(chain);
103+
if (zkSyncChain) {
104+
// zksync chains dont support deploying code with eth_call
105+
// need to call a deployed contract instead
106+
verificationData = {
107+
to: ZKSYNC_VALIDATOR_ADDRESS,
108+
data: encodeFunctionData({
109+
abi: universalSignatureValidatorAbi,
110+
functionName: "isValidSig",
111+
args: [address, hash, wrappedSignature],
112+
}),
113+
};
114+
} else {
115+
verificationData = {
116+
data: encodeDeployData({
117+
abi: universalSignatureValidatorAbi,
118+
args: [address, hash, wrappedSignature],
119+
bytecode: universalSignatureValidatorByteCode,
120+
}),
121+
};
122+
}
101123

102124
const rpcRequest = getRpcClient({
103125
chain,
104126
client,
105127
});
106128

107129
try {
108-
const result = await eth_call(rpcRequest, {
109-
data: verificationData,
110-
});
111-
112-
const hexResult = isHex(result) ? toBytes(result) : result;
113-
return equalBytes(hexResult, toBytes(true));
130+
const result = await eth_call(rpcRequest, verificationData);
131+
return hexToBool(result);
114132
} catch {
115133
// Some chains do not support the eth_call simulation and will fail, so we fall back to regular EIP1271 validation
116134
const validEip1271 = await verifyEip1271Signature({
@@ -121,7 +139,10 @@ export async function verifyHash({
121139
address,
122140
client,
123141
}),
124-
}).catch(() => false);
142+
}).catch((err) => {
143+
console.error("Error verifying EIP-1271 signature", err);
144+
return false;
145+
});
125146
if (validEip1271) {
126147
return true;
127148
}

packages/thirdweb/src/auth/verify-signature.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ export async function verifySignature(options: VerifySignatureParams) {
152152
if (isVerifyContractWalletSignatureParams(options)) {
153153
try {
154154
return await verifyContractWalletSignature(options);
155-
} catch {
155+
} catch (err) {
156+
console.error("Error verifying smart contract wallet signature", err);
156157
// no-op we skip to return false
157158
}
158159
} else if (!warningTriggered) {

0 commit comments

Comments
 (0)