From 889cef7fdf05b15b32579a2fa16c59ebaede8036 Mon Sep 17 00:00:00 2001 From: jaybuidl Date: Tue, 3 Oct 2023 23:52:08 +0100 Subject: [PATCH] feat: use eip712 typed structured data signing --- web/netlify/functions/update-settings.ts | 18 +++++++------- web/src/consts/eip712-messages.ts | 24 +++++++++++++++++++ .../SendMeNotifications/FormNotifs/index.tsx | 18 +++++++------- 3 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 web/src/consts/eip712-messages.ts diff --git a/web/netlify/functions/update-settings.ts b/web/netlify/functions/update-settings.ts index d4695f048..96897396a 100644 --- a/web/netlify/functions/update-settings.ts +++ b/web/netlify/functions/update-settings.ts @@ -1,7 +1,7 @@ import { Handler } from "@netlify/functions"; -import { verifyMessage } from "viem"; +import { verifyTypedData } from "viem"; import { createClient } from "@supabase/supabase-js"; -import { arbitrumGoerli } from "viem/chains"; +import messages from "../../src/consts/eip712-messages"; const SUPABASE_KEY = process.env.SUPABASE_CLIENT_API_KEY; const SUPABASE_URL = process.env.SUPABASE_URL; @@ -12,17 +12,15 @@ export const handler: Handler = async (event) => { if (!event.body) { throw new Error("No body provided"); } - // TODO: sanitize the body + // TODO: sanitize event.body const { email, telegram, nonce, address, signature } = JSON.parse(event.body); const lowerCaseAddress = address.toLowerCase() as `0x${string}`; - const data = { - address: lowerCaseAddress, - message: `Email:${email},Nonce:${nonce}`, - signature, - }; // Note: this does NOT work for smart contract wallets, but viem's publicClient.verifyMessage() fails to verify atm. - // https://viem.sh/docs/utilities/verifyMessage.html - const isValid = await verifyMessage(data); + // https://viem.sh/docs/utilities/verifyTypedData.html + const isValid = await verifyTypedData({ + ...messages.contactDetails(address, nonce, telegram, email), + signature, + }); if (!isValid) { // If the recovered address does not match the provided address, return an error throw new Error("Signature verification failed"); diff --git a/web/src/consts/eip712-messages.ts b/web/src/consts/eip712-messages.ts new file mode 100644 index 000000000..01ba1494d --- /dev/null +++ b/web/src/consts/eip712-messages.ts @@ -0,0 +1,24 @@ +export default { + contactDetails: (address: `0x${string}`, nonce, telegram = "", email = "") => + ({ + address: address.toLowerCase() as `0x${string}`, + domain: { + name: "Kleros v2", + version: "1", + chainId: 421_613, + }, + types: { + ContactDetails: [ + { name: "email", type: "string" }, + { name: "telegram", type: "string" }, + { name: "nonce", type: "string" }, + ], + }, + primaryType: "ContactDetails", + message: { + email, + telegram, + nonce, + }, + } as const), +}; diff --git a/web/src/layout/Header/navbar/Menu/Settings/SendMeNotifications/FormNotifs/index.tsx b/web/src/layout/Header/navbar/Menu/Settings/SendMeNotifications/FormNotifs/index.tsx index bd3d34d9f..7dc560087 100644 --- a/web/src/layout/Header/navbar/Menu/Settings/SendMeNotifications/FormNotifs/index.tsx +++ b/web/src/layout/Header/navbar/Menu/Settings/SendMeNotifications/FormNotifs/index.tsx @@ -4,6 +4,7 @@ import { useWalletClient, useAccount } from "wagmi"; import { Button } from "@kleros/ui-components-library"; import { uploadSettingsToSupabase } from "utils/uploadSettingsToSupabase"; import FormContact from "./FormContact"; +import messages from "../../../../../../../consts/eip712-messages"; const FormContainer = styled.form` position: relative; @@ -36,14 +37,15 @@ const FormNotifs: React.FC = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); + if (!address) { + throw new Error("Missing address"); + } const nonce = new Date().getTime().toString(); - const signature = await walletClient?.signMessage({ - account: address, - message: `Email:${emailInput},Nonce:${nonce}`, - }); - if (!address || !signature) { - console.error("Missing address or signature"); - return; + const signature = await walletClient?.signTypedData( + messages.contactDetails(address, nonce, telegramInput, emailInput) + ); + if (!signature) { + throw new Error("Missing signature"); } const data = { email: emailInput, @@ -80,7 +82,7 @@ const FormNotifs: React.FC = () => { -