diff --git a/apps/api/src/app/groups/groups.service.ts b/apps/api/src/app/groups/groups.service.ts index a6d241b1..274a130a 100644 --- a/apps/api/src/app/groups/groups.service.ts +++ b/apps/api/src/app/groups/groups.service.ts @@ -1,4 +1,4 @@ -import { BandadaContract, getBandadaContract, Network } from "@bandada/utils" +// import { BandadaContract, getBandadaContract, Network } from "@bandada/utils" import { id } from "@ethersproject/hash" import { BadRequestException, @@ -23,7 +23,7 @@ import { MerkleProof } from "./types" @Injectable() export class GroupsService { private cachedGroups: Map - private bandadaContract: BandadaContract + // private bandadaContract: BandadaContract constructor( @InjectRepository(Group) @@ -34,11 +34,11 @@ export class GroupsService { private readonly invitesService: InvitesService ) { this.cachedGroups = new Map() - this.bandadaContract = getBandadaContract( - process.env.ETHEREUM_NETWORK as Network, - process.env.BACKEND_PRIVATE_KEY as string, - process.env.INFURA_API_KEY as string - ) + // this.bandadaContract = getBandadaContract( + // process.env.ETHEREUM_NETWORK as Network, + // process.env.BACKEND_PRIVATE_KEY as string, + // process.env.INFURA_API_KEY as string + // ) } /** @@ -697,24 +697,24 @@ export class GroupsService { return fingerprints } - private async _updateFingerprintDuration( - groupId: string, - duration: number - ): Promise { - try { - await this.bandadaContract.updateFingerprintDuration( - BigInt(groupId), - BigInt(duration) - ) - Logger.log( - `GroupsService: group '${groupId}' fingerprint duration has been updated in the contract` - ) - } catch { - Logger.log( - `GroupsService: failed to update fingerprint duration contract groups` - ) - } - } + // private async _updateFingerprintDuration( + // groupId: string, + // duration: number + // ): Promise { + // try { + // await this.bandadaContract.updateFingerprintDuration( + // BigInt(groupId), + // BigInt(duration) + // ) + // Logger.log( + // `GroupsService: group '${groupId}' fingerprint duration has been updated in the contract` + // ) + // } catch { + // Logger.log( + // `GroupsService: failed to update fingerprint duration contract groups` + // ) + // } + // } private async _cacheGroups() { const groups = await this.getGroups() @@ -739,42 +739,42 @@ export class GroupsService { Logger.log(`GroupsService: ${groups.length} groups have been cached`) } - /** - * If the off-chain groups roots don't match the contract's ones, it updates them. - */ - /* istanbul ignore next */ - private async _syncContractGroups() { - const contractGroups = await this.bandadaContract.getGroups() - const fingerprints = new Set( - contractGroups.map(({ fingerprint }) => fingerprint.toString()) - ) - - for (const [, group] of this.cachedGroups) { - if (!fingerprints.has(group.root.toString())) { - this._updateContractGroup(group) - } - } - } - - /** - * Update the fingerprint of the group in the contract. - * @param group Off-chain group. - */ - /* istanbul ignore next */ - private async _updateContractGroup(group: CachedGroup): Promise { - try { - await this.bandadaContract.updateGroups([ - { - id: BigInt(group.id), - fingerprint: BigInt(group.root) - } - ]) - - Logger.log( - `GroupsService: group '${group.id}' has been updated in the contract` - ) - } catch { - Logger.error(`GroupsService: failed to update contract groups`) - } - } + // /** + // * If the off-chain groups roots don't match the contract's ones, it updates them. + // */ + // /* istanbul ignore next */ + // private async _syncContractGroups() { + // const contractGroups = await this.bandadaContract.getGroups() + // const fingerprints = new Set( + // contractGroups.map(({ fingerprint }) => fingerprint.toString()) + // ) + + // for (const [, group] of this.cachedGroups) { + // if (!fingerprints.has(group.root.toString())) { + // this._updateContractGroup(group) + // } + // } + // } + + // /** + // * Update the fingerprint of the group in the contract. + // * @param group Off-chain group. + // */ + // /* istanbul ignore next */ + // private async _updateContractGroup(group: CachedGroup): Promise { + // try { + // await this.bandadaContract.updateGroups([ + // { + // id: BigInt(group.id), + // fingerprint: BigInt(group.root) + // } + // ]) + + // Logger.log( + // `GroupsService: group '${group.id}' has been updated in the contract` + // ) + // } catch { + // Logger.error(`GroupsService: failed to update contract groups`) + // } + // } } diff --git a/apps/contracts/contracts/README.md b/apps/contracts/contracts/README.md index 51c41414..16d44681 100644 --- a/apps/contracts/contracts/README.md +++ b/apps/contracts/contracts/README.md @@ -98,4 +98,4 @@ yarn deploy:bandada yarn deploy:bandada-semaphore ``` -If you want to deploy contracts on Goerli or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file. +If you want to deploy contracts on Sepolia or Arbitrum, remember to provide a valid private key and an Infura API in your `.env` file. diff --git a/apps/contracts/hardhat.config.ts b/apps/contracts/hardhat.config.ts index 7234c075..7af7fc33 100644 --- a/apps/contracts/hardhat.config.ts +++ b/apps/contracts/hardhat.config.ts @@ -26,9 +26,9 @@ function getNetworks(): NetworksUserConfig { chainId: 1337, accounts }, - goerli: { - url: `https://goerli.infura.io/v3/${infuraApiKey}`, - chainId: 5, + sepolia: { + url: `https://sepolia.infura.io/v3/${infuraApiKey}`, + chainId: 11155111, accounts }, arbitrum: { diff --git a/apps/dashboard/.env.local b/apps/dashboard/.env.local index f13ec2e8..c2155d01 100644 --- a/apps/dashboard/.env.local +++ b/apps/dashboard/.env.local @@ -3,7 +3,7 @@ VITE_API_URL=http://localhost:3000 VITE_CLIENT_URL=http://localhost:3002 VITE_CLIENT_INVITES_URL=http://localhost:3002?inviteCode=\ -VITE_ETHEREUM_NETWORK=goerli +VITE_ETHEREUM_NETWORK=sepolia VITE_GITHUB_CLIENT_ID=a83a8b014ef38270fb22 VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ VITE_TWITTER_REDIRECT_URI=http://localhost:3001/credentials diff --git a/apps/dashboard/.env.production b/apps/dashboard/.env.production index 7de16412..cc4b6bbc 100644 --- a/apps/dashboard/.env.production +++ b/apps/dashboard/.env.production @@ -3,7 +3,7 @@ VITE_API_URL=https://api.bandada.pse.dev VITE_CLIENT_URL=https://client.bandada.pse.dev VITE_CLIENT_INVITES_URL=https://client.bandada.pse.dev?inviteCode=\ -VITE_ETHEREUM_NETWORK=goerli +VITE_ETHEREUM_NETWORK=sepolia VITE_GITHUB_CLIENT_ID=6ccd7b93e84260e353f9 VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ VITE_TWITTER_REDIRECT_URI=https://bandada.pse.dev/credentials diff --git a/apps/dashboard/.env.staging b/apps/dashboard/.env.staging index 1fcc1eba..ae74dd3d 100644 --- a/apps/dashboard/.env.staging +++ b/apps/dashboard/.env.staging @@ -3,7 +3,7 @@ VITE_API_URL=https://api-staging.bandada.pse.dev VITE_CLIENT_URL=https://client-staging.bandada.pse.dev VITE_CLIENT_INVITES_URL=https://client-staging.bandada.pse.dev?inviteCode=\ -VITE_ETHEREUM_NETWORK=goerli +VITE_ETHEREUM_NETWORK=sepolia VITE_GITHUB_CLIENT_ID=6ccd7b93e84260e353f9 VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ VITE_TWITTER_REDIRECT_URI=https://staging.bandada.pse.dev/credentials diff --git a/apps/dashboard/src/api/semaphoreAPI.ts b/apps/dashboard/src/api/semaphoreAPI.ts index 3409fca8..47a8ac0f 100644 --- a/apps/dashboard/src/api/semaphoreAPI.ts +++ b/apps/dashboard/src/api/semaphoreAPI.ts @@ -63,3 +63,38 @@ export async function getGroup(groupId: string): Promise { return null } } + +/** + * It returns the Semaphore on-chain groups on Goerli for a specific admin. + * @param adminAddress The admin address. + * @returns The list of groups. + */ +export async function getGoerliGroups( + adminAddress: string +): Promise { + const goerliSubgraph = new SemaphoreSubgraph("goerli") + + try { + const groups = await goerliSubgraph.getGroups({ + members: true, + filters: { admin: adminAddress } + }) + + return groups.map((group) => { + const groupName = parseGroupName(group.id) + + return { + id: group.id, + name: groupName, + treeDepth: group.merkleTree.depth, + members: group.members as string[], + admin: group.admin as string, + type: "on-chain" + } + }) + } catch (error) { + console.error(error) + + return null + } +} diff --git a/apps/dashboard/src/components/add-member-modal.tsx b/apps/dashboard/src/components/add-member-modal.tsx index 96a8f7cd..cb4ce993 100644 --- a/apps/dashboard/src/components/add-member-modal.tsx +++ b/apps/dashboard/src/components/add-member-modal.tsx @@ -130,7 +130,7 @@ ${memberIds.join("\n")} } try { - const semaphore = getSemaphoreContract("goerli", signer as any) + const semaphore = getSemaphoreContract("sepolia", signer as any) await semaphore.addMembers(group.name, memberIds) @@ -138,7 +138,7 @@ ${memberIds.join("\n")} onClose(memberIds) } catch (error) { alert( - "Some error occurred! Check if you're on Goerli network and the transaction is signed and completed" + "Some error occurred! Check if you're on Sepolia network and the transaction is signed and completed" ) setIsLoading(false) diff --git a/apps/dashboard/src/components/goerli-group.tsx b/apps/dashboard/src/components/goerli-group.tsx new file mode 100644 index 00000000..712dd8f9 --- /dev/null +++ b/apps/dashboard/src/components/goerli-group.tsx @@ -0,0 +1,63 @@ +import { + Box, + Icon, + IconButton, + Input, + InputGroup, + InputRightElement, + Text, + Tooltip, + useClipboard +} from "@chakra-ui/react" +import { FiCopy } from "react-icons/fi" + +export type GoerliGroupCardProps = { + name: string + id: string +} + +export default function GoerliGroupCard({ + name, + id +}: GoerliGroupCardProps): JSX.Element { + const { hasCopied: hasCopiedGroupId, onCopy: onCopyGroupId } = + useClipboard(id) + return ( + + {name} + + + + + + + e.preventDefault()} + icon={ + + } + /> + + + + + ) +} diff --git a/apps/dashboard/src/components/new-group-stepper/final-preview-step.tsx b/apps/dashboard/src/components/new-group-stepper/final-preview-step.tsx index fef741d3..02a28704 100644 --- a/apps/dashboard/src/components/new-group-stepper/final-preview-step.tsx +++ b/apps/dashboard/src/components/new-group-stepper/final-preview-step.tsx @@ -25,7 +25,7 @@ export default function FinalPreviewStep({ if (group.type === "on-chain" && signer) { setLoading(true) try { - const semaphore = getSemaphoreContract("goerli", signer as any) + const semaphore = getSemaphoreContract("sepolia", signer as any) const admin = await signer.getAddress() await semaphore.createGroup(group.name, group.treeDepth, admin) @@ -35,7 +35,7 @@ export default function FinalPreviewStep({ } catch (error) { setLoading(false) alert( - "Some error occurred! Check if you're on Goerli network and the transaction is signed and completed" + "Some error occurred! Check if you're on Sepolia network and the transaction is signed and completed" ) console.error(error) diff --git a/apps/dashboard/src/context/auth-context.tsx b/apps/dashboard/src/context/auth-context.tsx index 3b9dfe72..4cce653b 100644 --- a/apps/dashboard/src/context/auth-context.tsx +++ b/apps/dashboard/src/context/auth-context.tsx @@ -15,7 +15,7 @@ import { import React, { ReactNode, useEffect, useMemo, useState } from "react" import { SiweMessage } from "siwe" import { configureChains, createClient, WagmiConfig } from "wagmi" -import { goerli } from "wagmi/chains" +import { sepolia } from "wagmi/chains" import { publicProvider } from "wagmi/providers/public" import { getNonce, logOut, signIn } from "../api/bandadaAPI" import useSessionData from "../hooks/use-session-data" @@ -83,7 +83,7 @@ export function AuthContextProvider({ children }: { children: ReactNode }) { ) const { chains, provider, webSocketProvider } = configureChains( - [goerli], + [sepolia], [publicProvider()] ) diff --git a/apps/dashboard/src/pages/groups.tsx b/apps/dashboard/src/pages/groups.tsx index 688ec5ea..1f810443 100644 --- a/apps/dashboard/src/pages/groups.tsx +++ b/apps/dashboard/src/pages/groups.tsx @@ -11,21 +11,28 @@ import { InputRightElement, Spinner, Text, - VStack + VStack, + Stack, + Link as ChakraLink } from "@chakra-ui/react" import { useCallback, useContext, useEffect, useState } from "react" import { FiSearch } from "react-icons/fi" import { Link, useNavigate } from "react-router-dom" import { getGroups as getOffchainGroups } from "../api/bandadaAPI" -import { getGroups as getOnchainGroups } from "../api/semaphoreAPI" +import { + getGroups as getOnchainGroups, + getGoerliGroups +} from "../api/semaphoreAPI" import GroupCard from "../components/group-card" import { AuthContext } from "../context/auth-context" import { Group } from "../types" +import GoerliGroupCard from "../components/goerli-group" export default function GroupsPage(): JSX.Element { const { admin } = useContext(AuthContext) const [_isLoading, setIsLoading] = useState(false) const [_groups, setGroups] = useState([]) + const [_goerliGroups, setGoerliGroups] = useState([]) const [_searchField, setSearchField] = useState("") const navigate = useNavigate() @@ -51,6 +58,11 @@ export default function GroupsPage(): JSX.Element { }) ]) + const goerliGroups = await getGoerliGroups(admin.address) + if (goerliGroups) { + setGoerliGroups((groups) => [...groups, ...goerliGroups]) + } + setIsLoading(false) } })() @@ -150,6 +162,36 @@ export default function GroupsPage(): JSX.Element { ))} )} + + {!_isLoading && _goerliGroups.length > 0 && ( + + + Groups on Goerli (name/id) + + The Goerli network is deprecated. + + {_goerliGroups.map((group) => ( + + ))} + + + To fetch more information about the Goerli groups + you can use the{" "} + + @semaphore-protocol/data + {" "} + package. + + + )} ) diff --git a/apps/dashboard/src/pages/home.tsx b/apps/dashboard/src/pages/home.tsx index b853c450..2c19895c 100644 --- a/apps/dashboard/src/pages/home.tsx +++ b/apps/dashboard/src/pages/home.tsx @@ -74,7 +74,7 @@ export default function HomePage(): JSX.Element { diff --git a/libs/utils/README.md b/libs/utils/README.md index 49b4144b..0ff2a640 100644 --- a/libs/utils/README.md +++ b/libs/utils/README.md @@ -159,5 +159,5 @@ Returns the contract addresses for the Bandada, Semaphore and BandadaSemaphore s ```ts import { getContractAddresses } from "@bandada/utils" -const addresses = getContractAddresses("goerli") +const addresses = getContractAddresses("sepolia") ``` diff --git a/libs/utils/src/contractAddresses.ts b/libs/utils/src/contractAddresses.ts index 10afd856..cd3713ef 100644 --- a/libs/utils/src/contractAddresses.ts +++ b/libs/utils/src/contractAddresses.ts @@ -9,10 +9,10 @@ const CONTRACT_ADDRESSES: { [K in Network]: { [Y in ContractName]: string } } = Bandada: "0x5fbdb2315678afecb367f032d93f642f64180aa3", BandadaSemaphore: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512" }, - goerli: { + sepolia: { Semaphore: "0x3889927F0B5Eb1a02C6E2C20b39a1Bd4EAd76131", - Bandada: "0xB6f17dB678Dab765bC684Fd6BaA0F222Af388F77", - BandadaSemaphore: "0xa0Bf12642C66Fc17d706D3FA7C9eB8EfAEA67d02" + Bandada: "0xD2873C967079D8B1eAd9dc86B8F8f3948e29564E", + BandadaSemaphore: "0x35ce7AFd20b031b4EEa83748D15f319Be9378d2C" } } diff --git a/libs/utils/src/getProvider.ts b/libs/utils/src/getProvider.ts index f99d4714..b5d8e391 100644 --- a/libs/utils/src/getProvider.ts +++ b/libs/utils/src/getProvider.ts @@ -10,7 +10,7 @@ export default function getProvider( switch (network) { case "localhost": return new JsonRpcProvider("http://127.0.0.1:8545") - case "goerli": + case "sepolia": return new InfuraProvider(network, apiKey) default: throw new TypeError(`'${network}' network is not supported`) diff --git a/libs/utils/src/types/index.ts b/libs/utils/src/types/index.ts index c621a892..12d9f8bf 100644 --- a/libs/utils/src/types/index.ts +++ b/libs/utils/src/types/index.ts @@ -1,15 +1,5 @@ // Supported networks: https://docs.ethers.org/v5/api/providers/api-providers/#InfuraProvider -export type Network = - | "localhost" - // | "homestead" - | "goerli" -// | "sepolia" -// | "arbitrum" -// | "arbitrum-goerli" -// | "matic" -// | "maticmum" -// | "optimism" -// | "optimism-goerli" +export type Network = "localhost" | "sepolia" export type ContractName = "Bandada" | "Semaphore" | "BandadaSemaphore" diff --git a/package.json b/package.json index fe012f63..0c028edf 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "private": true, "scripts": { "start": "yarn workspaces foreach --exclude bandada-docs -A -pi run start", - "dev": "yarn workspaces foreach -A -pi run dev", + "dev": "yarn workspaces foreach --exclude contracts -A -pi run dev", "test": "jest && yarn workspace contracts test", "test:coverage": "yarn test:jest:coverage && yarn test:contracts:coverage", "test:jest:coverage": "jest --coverage",