From c031d884823f642fb478bb2199f10a581d8d847d Mon Sep 17 00:00:00 2001 From: zkFriendly Date: Mon, 26 Feb 2024 16:05:56 +0100 Subject: [PATCH 1/2] feat(web-app): integrate gelato relayer --- .env.example | 1 + apps/web-app/next.config.mjs | 3 +- apps/web-app/src/app/group/page.tsx | 39 +++++++++++++++++++++---- apps/web-app/src/app/proofs/page.tsx | 43 +++++++++++++++++++++++----- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/.env.example b/.env.example index 57a673d..4adf200 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,4 @@ ETHEREUM_PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f REPORT_GAS=false COINMARKETCAP_API_KEY= ETHERSCAN_API_KEY= +GELATO_RELAYER_API_KEY= diff --git a/apps/web-app/next.config.mjs b/apps/web-app/next.config.mjs index 5788cd9..4ac1d1a 100644 --- a/apps/web-app/next.config.mjs +++ b/apps/web-app/next.config.mjs @@ -14,7 +14,8 @@ const nextConfig = withPWA({ })({ env: { INFURA_API_KEY: process.env.INFURA_API_KEY, - ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY + ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY, + GELATO_RELAYER_API_KEY: process.env.GELATO_RELAYER_API_KEY }, output: "export" }) diff --git a/apps/web-app/src/app/group/page.tsx b/apps/web-app/src/app/group/page.tsx index 380f36a..4996e60 100644 --- a/apps/web-app/src/app/group/page.tsx +++ b/apps/web-app/src/app/group/page.tsx @@ -1,5 +1,4 @@ "use client" - import Stepper from "@/components/Stepper" import LogsContext from "@/context/LogsContext" import SemaphoreContext from "@/context/SemaphoreContext" @@ -9,6 +8,7 @@ import { Identity } from "@semaphore-protocol/core" import { useRouter } from "next/navigation" import { useCallback, useContext, useEffect, useState } from "react" import Feedback from "../../../contract-artifacts/Feedback.json" +import { ethers } from "ethers" export default function GroupsPage() { const router = useRouter() @@ -42,10 +42,10 @@ export default function GroupsPage() { setLoading.on() setLogs(`Joining the Feedback group...`) - let response: any + let joinedGroup: boolean = false if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) { - response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, { + const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ @@ -55,17 +55,46 @@ export default function GroupsPage() { functionParameters: [_identity.commitment.toString()] }) }) + + if (response.status === 200) { + joinedGroup = true + } + } else if ( + process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT && + process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID && + process.env.GELATO_RELAYER_API_KEY + ) { + const iface = new ethers.Interface(Feedback.abi) + const request = { + chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID, + target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS, + data: iface.encodeFunctionData("joinGroup", [_identity.commitment.toString()]), + sponsorApiKey: process.env.GELATO_RELAYER_API_KEY + } + const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(request) + }) + + if (response.status === 201) { + joinedGroup = true + } } else { - response = await fetch("api/join", { + const response = await fetch("api/join", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ identityCommitment: _identity.commitment.toString() }) }) + + if (response.status === 200) { + joinedGroup = true + } } - if (response.status === 200) { + if (joinedGroup) { addUser(_identity.commitment.toString()) setLogs(`You have joined the Feedback group event 🎉 Share your feedback anonymously!`) diff --git a/apps/web-app/src/app/proofs/page.tsx b/apps/web-app/src/app/proofs/page.tsx index 26f9861..08dd63b 100644 --- a/apps/web-app/src/app/proofs/page.tsx +++ b/apps/web-app/src/app/proofs/page.tsx @@ -6,7 +6,7 @@ import SemaphoreContext from "@/context/SemaphoreContext" import IconRefreshLine from "@/icons/IconRefreshLine" import { Box, Button, Divider, Heading, HStack, Link, Text, useBoolean, VStack } from "@chakra-ui/react" import { generateProof, Group, Identity } from "@semaphore-protocol/core" -import { encodeBytes32String } from "ethers" +import { encodeBytes32String, ethers } from "ethers" import { useRouter } from "next/navigation" import { useCallback, useContext, useEffect, useState } from "react" import Feedback from "../../../contract-artifacts/Feedback.json" @@ -64,21 +64,46 @@ export default function ProofsPage() { process.env.NEXT_PUBLIC_GROUP_ID as string ) - let response: any - + let feedbackSent: boolean = false + const params = [merkleTreeDepth, merkleTreeRoot, nullifier, message, points] if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) { - response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, { + const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ abi: Feedback.abi, address: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS, functionName: "sendFeedback", - functionParameters: [merkleTreeDepth, merkleTreeRoot, nullifier, message, points] + functionParameters: params }) }) + + if (response.status === 200) { + feedbackSent = true + } + } else if ( + process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT && + process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID && + process.env.GELATO_RELAYER_API_KEY + ) { + const iface = new ethers.Interface(Feedback.abi) + const request = { + chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID, + target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS, + data: iface.encodeFunctionData("sendFeedback", params), + sponsorApiKey: process.env.GELATO_RELAYER_API_KEY + } + const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(request) + }) + + if (response.status === 201) { + feedbackSent = true + } } else { - response = await fetch("api/feedback", { + const response = await fetch("api/feedback", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ @@ -89,9 +114,13 @@ export default function ProofsPage() { points }) }) + + if (response.status === 200) { + feedbackSent = true + } } - if (response.status === 200) { + if (feedbackSent) { addFeedback(feedback) setLogs(`Your feedback has been posted 🎉`) From 94d88b46da464d355d4144d0add659d6cb673d96 Mon Sep 17 00:00:00 2001 From: zkFriendly Date: Mon, 4 Mar 2024 21:43:11 +0100 Subject: [PATCH 2/2] chore(web-app): add gelato env variables --- apps/web-app/.env.production | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web-app/.env.production b/apps/web-app/.env.production index 1236cd0..82bd297 100644 --- a/apps/web-app/.env.production +++ b/apps/web-app/.env.production @@ -2,4 +2,6 @@ NEXT_PUBLIC_DEFAULT_NETWORK=sepolia NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=0xC6446BB589E141fFACeaCd91953CbB0F2055C7e5 NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS=0x5B8e7cC7bAC61A4b952d472b67056B2f260ba6dc NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK=https://api.defender.openzeppelin.com/actions/20fce2ae-844b-4ec0-a6a2-90a3350a9d2c/runs/webhook/303216d1-fa7d-4fca-8c5b-7ba1ba544fc7/2T7i9xrkZA5j37hoaQLUuw +NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT=https://api.gelato.digital/relays/v2/sponsored-call +NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID=11155111 NEXT_PUBLIC_GROUP_ID=9