Skip to content

Commit 84a0254

Browse files
detect primary type if missing in sign typed data input (#885)
* detect primary type if missing in sign typed data input * lint * extra bun
1 parent 377656d commit 84a0254

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

src/server/routes/backend-wallet/sign-typed-data.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type Static, Type } from "@sinclair/typebox";
2+
import { ethers } from "ethers";
23
import type { FastifyInstance } from "fastify";
34
import { StatusCodes } from "http-status-codes";
45
import { arbitrumSepolia } from "thirdweb/chains";
@@ -60,6 +61,15 @@ export async function signTypedData(fastify: FastifyInstance) {
6061

6162
const chain = chainId ? await getChain(chainId) : arbitrumSepolia;
6263

64+
let parsedPrimaryType = primaryType;
65+
if (!parsedPrimaryType) {
66+
// try to detect the primary type, which requires removing the EIP712Domain type
67+
// biome-ignore lint/performance/noDelete: need to delete explicitely
68+
delete (types as unknown as Record<string, unknown>).EIP712Domain;
69+
parsedPrimaryType =
70+
ethers.utils._TypedDataEncoder.getPrimaryType(types);
71+
}
72+
6373
const { account } = await walletDetailsToAccount({
6474
walletDetails,
6575
chain,
@@ -68,7 +78,7 @@ export async function signTypedData(fastify: FastifyInstance) {
6878
const result = await account.signTypedData({
6979
domain,
7080
types,
71-
primaryType,
81+
primaryType: parsedPrimaryType,
7282
message: value,
7383
} as never);
7484

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { describe, expect, test } from "bun:test";
2+
import { signTypedData } from "thirdweb/utils";
3+
import { ANVIL_PKEY_A } from "../../utils/wallets";
4+
import { setup } from "../setup";
5+
6+
describe("signTypedDataRoute", () => {
7+
const data = {
8+
domain: {
9+
name: "Ether Mail",
10+
version: "1",
11+
chainId: 1,
12+
verifyingContract: "0x0000000000000000000000000000000000000000",
13+
},
14+
message: {
15+
contents: "Hello, Bob!",
16+
from: {
17+
name: "Alice",
18+
},
19+
},
20+
primaryType: "Mail",
21+
types: {
22+
EIP712Domain: [
23+
{ name: "name", type: "string" },
24+
{ name: "version", type: "string" },
25+
{ name: "chainId", type: "uint256" },
26+
{ name: "verifyingContract", type: "address" },
27+
],
28+
Mail: [
29+
{ name: "contents", type: "string" },
30+
{ name: "from", type: "Person" },
31+
],
32+
Person: [{ name: "name", type: "string" }],
33+
},
34+
} as const;
35+
36+
test("Sign typed data", async () => {
37+
const { engine, backendWallet } = await setup();
38+
39+
const res = await engine.backendWallet.signTypedData(backendWallet, {
40+
domain: data.domain,
41+
value: data.message,
42+
types: data.types,
43+
primaryType: data.primaryType,
44+
});
45+
46+
const expected = signTypedData({
47+
// @ts-expect-error - bigint serialization
48+
domain: data.domain,
49+
message: data.message,
50+
types: data.types,
51+
primaryType: data.primaryType,
52+
privateKey: ANVIL_PKEY_A,
53+
});
54+
55+
expect(res.result).toEqual(expected);
56+
});
57+
58+
test("Sign typed data without primary type", async () => {
59+
const { engine, backendWallet } = await setup();
60+
61+
const res = await engine.backendWallet.signTypedData(backendWallet, {
62+
domain: data.domain,
63+
value: data.message,
64+
types: data.types,
65+
});
66+
67+
const expected = signTypedData({
68+
// @ts-expect-error - bigint serialization
69+
domain: data.domain,
70+
message: data.message,
71+
types: data.types,
72+
primaryType: data.primaryType,
73+
privateKey: ANVIL_PKEY_A,
74+
});
75+
76+
expect(res.result).toEqual(expected);
77+
});
78+
});

0 commit comments

Comments
 (0)