From 78d5af4683631ca24e861d5e746b211192942fe8 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 25 Apr 2024 13:36:50 +0200 Subject: [PATCH] Sign Typed Data --- src/chains/ethereum.ts | 43 +++++++++++++++++++++++++++++++++++++----- tests/e2e.test.ts | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/chains/ethereum.ts b/src/chains/ethereum.ts index c84eb50..749d02b 100644 --- a/src/chains/ethereum.ts +++ b/src/chains/ethereum.ts @@ -11,7 +11,11 @@ import { isBytes, SignableMessage, verifyMessage, + verifyTypedData, signatureToHex, + hashTypedData, + TypedData, + TypedDataDefinition, } from "viem"; import { BaseTx, @@ -211,19 +215,48 @@ export class NearEthAdapter { } // Below code is inspired by https://github.com/Connor-ETHSeoul/near-viem + async signTypedData< + const typedData extends TypedData | Record, + primaryType extends keyof typedData | "EIP712Domain" = keyof typedData, + >(typedData: TypedDataDefinition): Promise { + const sigs = await this.sign(hashTypedData(typedData)); + + const common = { + address: this.ethPublicKey(), + types: typedData.types, + /* eslint-disable @typescript-eslint/no-explicit-any */ + primaryType: typedData.primaryType as any, + message: typedData.message as any, + domain: typedData.domain as any, + /* eslint-enable @typescript-eslint/no-explicit-any */ + }; + const validity = await Promise.all([ + verifyTypedData({ + signature: sigs[0], + ...common, + }), + verifyTypedData({ + signature: sigs[1], + ...common, + }), + ]); + return this.pickValidSignature(validity, sigs); + } + async signMessage(message: SignableMessage): Promise { const sigs = await this.sign(hashMessage(message)); - const address = this.ethPublicKey(); + const common = { + address: this.ethPublicKey(), + message, + }; const validity = await Promise.all([ verifyMessage({ - address, - message, signature: sigs[0], + ...common, }), verifyMessage({ - address, - message: message, signature: sigs[1], + ...common, }), ]); return this.pickValidSignature(validity, sigs); diff --git a/tests/e2e.test.ts b/tests/e2e.test.ts index f32e0e1..da3e29c 100644 --- a/tests/e2e.test.ts +++ b/tests/e2e.test.ts @@ -33,4 +33,46 @@ describe("End To End", () => { it("signMessage", async () => { await expect(evm.signMessage("NearEth")).resolves.not.toThrow(); }); + + it("signTypedData", async () => { + const message = { + from: { + name: "Cow", + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + }, + to: { + name: "Bob", + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + }, + contents: "Hello, Bob!", + } as const; + + const domain = { + name: "Ether Mail", + version: "1", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + } as const; + + const types = { + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, + ], + } as const; + + await expect( + evm.signTypedData({ + types, + primaryType: "Mail", + message, + domain, + }) + ).resolves.not.toThrow(); + }); });