diff --git a/apps/docs/package.json b/apps/docs/package.json index b4de2d237..889703377 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -16,6 +16,7 @@ "@docusaurus/core": "3.1.1", "@docusaurus/preset-classic": "3.1.1", "@mdx-js/react": "^3.0.0", + "@semaphore-protocol/utils": "4.0.0-beta.4", "@svgr/webpack": "^5.5.0", "clsx": "^1.2.1", "docusaurus-plugin-sass": "^0.2.5", diff --git a/apps/docs/src/components/DeployedContracts.tsx b/apps/docs/src/components/DeployedContracts.tsx index c7a3e1fb0..5c6de18f8 100644 --- a/apps/docs/src/components/DeployedContracts.tsx +++ b/apps/docs/src/components/DeployedContracts.tsx @@ -1,5 +1,5 @@ +import { deployedContracts } from "@semaphore-protocol/utils" import Heading from "@theme/Heading" -import { useEffect, useState } from "react" function capitalizeFirstLetter(s: string): string { return s.charAt(0).toUpperCase() + s.slice(1) @@ -23,17 +23,6 @@ function getEtherscanLink(network: string): string { } export default function DeployedContracts() { - const [deployedContracts, setDeployedContracts] = useState([]) - - useEffect(() => { - fetch( - "https://raw.githubusercontent.com/semaphore-protocol/semaphore/main/packages/contracts/deployed-contracts.json" - ) - .then((response) => response.json()) - .catch(() => []) - .then(setDeployedContracts) - }, []) - return (
{deployedContracts.map(({ network, contracts }) => ( diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index d3304d5ca..39881ac8f 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,5 +1,5 @@ import { GroupResponse, SemaphoreEthers, SemaphoreSubgraph } from "@semaphore-protocol/data" -import supportedNetworks from "@semaphore-protocol/utils/supported-networks" +import { supportedNetworks } from "@semaphore-protocol/utils/networks" import chalk from "chalk" import { program } from "commander" import decompress from "decompress" diff --git a/packages/contracts/deployed-contracts.json b/packages/contracts/deployed-contracts.json index 6aaf0a7db..c56554460 100644 --- a/packages/contracts/deployed-contracts.json +++ b/packages/contracts/deployed-contracts.json @@ -12,7 +12,8 @@ }, { "name": "Semaphore", - "address": "0x5B8e7cC7bAC61A4b952d472b67056B2f260ba6dc" + "address": "0x5B8e7cC7bAC61A4b952d472b67056B2f260ba6dc", + "startBlock": 5150903 } ] } diff --git a/packages/contracts/hardhat.config.ts b/packages/contracts/hardhat.config.ts index 0500f2401..c85c498b9 100644 --- a/packages/contracts/hardhat.config.ts +++ b/packages/contracts/hardhat.config.ts @@ -2,6 +2,7 @@ import "@nomicfoundation/hardhat-chai-matchers" import "@nomicfoundation/hardhat-ethers" import "@nomicfoundation/hardhat-verify" import "@openzeppelin/hardhat-upgrades" +import { SupportedNetwork } from "@semaphore-protocol/utils" import "@typechain/hardhat" import { config as dotenvConfig } from "dotenv" import "hardhat-gas-reporter" @@ -22,7 +23,7 @@ function getNetworks(): NetworksUserConfig { const infuraApiKey = process.env.INFURA_API_KEY const accounts = [`0x${process.env.BACKEND_PRIVATE_KEY}`] - return { + const networks: Record = { sepolia: { url: `https://sepolia.infura.io/v3/${infuraApiKey}`, chainId: 11155111, @@ -49,6 +50,8 @@ function getNetworks(): NetworksUserConfig { accounts } } + + return networks } const hardhatConfig: HardhatUserConfig = { diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 6438e2418..1f9bab4e3 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -21,6 +21,7 @@ "@nomicfoundation/hardhat-verify": "^2.0.0", "@openzeppelin/hardhat-upgrades": "^3.0.4", "@semaphore-protocol/core": "workspace:packages/core", + "@semaphore-protocol/utils": "workspace:packages/utils", "@typechain/ethers-v6": "^0.5.0", "@typechain/hardhat": "^9.0.0", "@types/chai": "^4.2.0", diff --git a/packages/contracts/scripts/utils.ts b/packages/contracts/scripts/utils.ts index 71d6d1fe2..4ac047542 100644 --- a/packages/contracts/scripts/utils.ts +++ b/packages/contracts/scripts/utils.ts @@ -1,8 +1,10 @@ +import { SupportedNetwork, supportedNetworks } from "@semaphore-protocol/utils" import { readFileSync, writeFileSync } from "fs" export type NetworkDeployedContracts = { name: "Semaphore" | "SemaphoreVerifier" | "PoseidonT3" address: string + startBlock?: number }[] export type DeployedContracts = { @@ -10,8 +12,6 @@ export type DeployedContracts = { contracts: NetworkDeployedContracts }[] -const supportedNetworks = ["sepolia", "arbitrum", "mumbai", "optimism-sepolia", "arbitrum-sepolia"] - export function getDeployedContracts(): DeployedContracts { return JSON.parse(readFileSync(`./deployed-contracts.json`, "utf8")) } @@ -38,7 +38,7 @@ export function getDeployedContractAddress(network: string, contractName: string return semaphoreAddress.address } -export function saveDeployedContracts(contracts: NetworkDeployedContracts, network?: string) { +export function saveDeployedContracts(contracts: NetworkDeployedContracts, network?: SupportedNetwork) { if (network && supportedNetworks.includes(network)) { const deployedContracts = getDeployedContracts() as DeployedContracts diff --git a/packages/contracts/tasks/deploy.ts b/packages/contracts/tasks/deploy.ts index af8224305..8b0657acf 100644 --- a/packages/contracts/tasks/deploy.ts +++ b/packages/contracts/tasks/deploy.ts @@ -1,3 +1,4 @@ +import { SupportedNetwork } from "@semaphore-protocol/utils" import { task, types } from "hardhat/config" import { saveDeployedContracts } from "../scripts/utils" import { deployContract } from "./utils" @@ -51,6 +52,8 @@ task("deploy", "Deploy a Semaphore contract") console.info(`Semaphore contract has been deployed to: ${semaphoreAddress}`) } + const deploymentTransaction = semaphore.deploymentTransaction() + saveDeployedContracts( [ { @@ -63,10 +66,14 @@ task("deploy", "Deploy a Semaphore contract") }, { name: "Semaphore", - address: semaphoreAddress + address: semaphoreAddress, + startBlock: + deploymentTransaction && deploymentTransaction.blockNumber + ? deploymentTransaction.blockNumber + : undefined } ], - hardhatArguments.network + hardhatArguments.network as SupportedNetwork ) return { diff --git a/packages/contracts/tasks/utils.ts b/packages/contracts/tasks/utils.ts index 2c0facb0d..79eaa9e29 100644 --- a/packages/contracts/tasks/utils.ts +++ b/packages/contracts/tasks/utils.ts @@ -11,11 +11,9 @@ export async function deployContract( if (network !== undefined && network !== "hardhat" && network !== "localhost") { contract = await defender.deployContract(contractFactory, args, { salt: process.env.CREATE2_SALT }) - - await contract.waitForDeployment() } else { contract = await contractFactory.deploy(...args) } - return contract + return contract.waitForDeployment() } diff --git a/packages/data/package.json b/packages/data/package.json index 8e785f442..e8d6a8904 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -37,6 +37,7 @@ "rollup-plugin-cleanup": "^3.2.1" }, "dependencies": { + "@semaphore-protocol/utils": "4.0.0-beta.4", "axios": "1.6.6", "ethers": "6.11.0" } diff --git a/packages/data/src/ethers.ts b/packages/data/src/ethers.ts index e6f790a39..fa6439b1f 100644 --- a/packages/data/src/ethers.ts +++ b/packages/data/src/ethers.ts @@ -1,3 +1,5 @@ +import { SupportedNetwork, getDeployedContract, supportedNetworks } from "@semaphore-protocol/utils" +import { defaultNetwork } from "@semaphore-protocol/utils/networks" import { ZeroAddress } from "ethers/constants" import { Contract } from "ethers/contract" import { @@ -25,7 +27,7 @@ export default class SemaphoreEthers { * @param networkOrEthereumURL Ethereum network or custom URL. * @param options Ethers options. */ - constructor(networkOrEthereumURL: EthersNetwork | string = "sepolia", options: EthersOptions = {}) { + constructor(networkOrEthereumURL: EthersNetwork | string = defaultNetwork, options: EthersOptions = {}) { checkParameter(networkOrEthereumURL, "networkOrSubgraphURL", "string") if (options.provider) { @@ -42,33 +44,17 @@ export default class SemaphoreEthers { networkOrEthereumURL = "maticmum" } - switch (networkOrEthereumURL) { - case "arbitrum": - options.address ??= "0xc60E0Ee1a2770d5F619858C641f14FC4a6401520" - options.startBlock ??= 77278430 - break - case "arbitrum-sepolia": - options.address ??= "0x3889927F0B5Eb1a02C6E2C20b39a1Bd4EAd76131" - options.startBlock ??= 15174410 - break - case "maticmum": - options.address ??= "0x3889927F0B5Eb1a02C6E2C20b39a1Bd4EAd76131" - options.startBlock ??= 33995010 - break - case "sepolia": - options.address ??= "0x5B8e7cC7bAC61A4b952d472b67056B2f260ba6dc" - options.startBlock ??= 5150903 - break - case "optimism-sepolia": - options.address ??= "0x3889927F0B5Eb1a02C6E2C20b39a1Bd4EAd76131" - options.startBlock ??= 7632846 - break - default: - if (options.address === undefined) { - throw new Error(`You should provide a Semaphore contract address for this network`) - } + if (supportedNetworks.includes(networkOrEthereumURL as SupportedNetwork)) { + const { address, startBlock } = getDeployedContract(networkOrEthereumURL as SupportedNetwork) + + options.address ??= address + options.startBlock ??= startBlock + } else { + if (options.address === undefined) { + throw new Error(`You should provide a Semaphore contract address for this network`) + } - options.startBlock ??= 0 + options.startBlock ??= 0 } let provider: Provider diff --git a/packages/data/src/getURL.ts b/packages/data/src/getURL.ts index 3ed218cad..23d2ec5e7 100644 --- a/packages/data/src/getURL.ts +++ b/packages/data/src/getURL.ts @@ -1,4 +1,4 @@ -import { SupportedNetwork } from "./types" +import type { SupportedNetwork } from "@semaphore-protocol/utils" /** * Returns the subgraph URL related to the network passed as a parameter. diff --git a/packages/data/src/subgraph.ts b/packages/data/src/subgraph.ts index 1480501b1..557fde198 100644 --- a/packages/data/src/subgraph.ts +++ b/packages/data/src/subgraph.ts @@ -1,8 +1,10 @@ +import type { SupportedNetwork } from "@semaphore-protocol/utils" +import { defaultNetwork } from "@semaphore-protocol/utils/networks" import { AxiosRequestConfig } from "axios" import checkParameter from "./checkParameter" import getURL from "./getURL" import request from "./request" -import { GroupOptions, GroupResponse, SupportedNetwork } from "./types" +import { GroupOptions, GroupResponse } from "./types" import { jsDateToGraphqlDate } from "./utils" export default class SemaphoreSubgraph { @@ -12,7 +14,7 @@ export default class SemaphoreSubgraph { * Initializes the subgraph object with one of the supported networks or a custom URL. * @param networkOrSubgraphURL Supported Semaphore network or custom Subgraph URL. */ - constructor(networkOrSubgraphURL: SupportedNetwork | string = SupportedNetwork.SEPOLIA) { + constructor(networkOrSubgraphURL: SupportedNetwork | string = defaultNetwork) { checkParameter(networkOrSubgraphURL, "networkOrSubgraphURL", "string") if (typeof networkOrSubgraphURL === "string" && networkOrSubgraphURL.startsWith("http")) { diff --git a/packages/data/src/types/index.ts b/packages/data/src/types/index.ts index 019c252bc..3b8ce08ce 100644 --- a/packages/data/src/types/index.ts +++ b/packages/data/src/types/index.ts @@ -1,11 +1,3 @@ -export enum SupportedNetwork { - SEPOLIA = "sepolia", - MUMBAI = "mumbai", - OPTIMISM_SEPOLIA = "optimism-sepolia", - ARBITRUM_SEPOLIA = "arbitrum-sepolia", - ARBITRUM = "arbitrum" -} - export type EthersNetwork = | "homestead" | "matic" diff --git a/packages/utils/package.json b/packages/utils/package.json index 7f528b2e9..692deaf99 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -12,10 +12,10 @@ "require": "./dist/index.cjs", "default": "./dist/index.js" }, - "./supported-networks": { - "types": "./dist/types/supported-networks.d.ts", - "require": "./dist/lib.commonjs/supported-networks.cjs", - "default": "./dist/lib.esm/supported-networks.js" + "./networks": { + "types": "./dist/types/networks.d.ts", + "require": "./dist/lib.commonjs/networks.cjs", + "default": "./dist/lib.esm/networks.js" }, "./constants": { "types": "./dist/types/constants.d.ts", @@ -47,6 +47,7 @@ "access": "public" }, "devDependencies": { + "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-typescript": "^11.1.6", "rimraf": "^5.0.5", "rollup": "^4.12.0", diff --git a/packages/utils/rollup.config.ts b/packages/utils/rollup.config.ts index 648363611..ed43a444c 100644 --- a/packages/utils/rollup.config.ts +++ b/packages/utils/rollup.config.ts @@ -1,4 +1,5 @@ import typescript from "@rollup/plugin-typescript" +import json from "@rollup/plugin-json" import * as fs from "fs" import cleanup from "rollup-plugin-cleanup" @@ -23,7 +24,8 @@ export default [ typescript({ tsconfig: "./build.tsconfig.json" }), - cleanup({ comments: "jsdoc" }) + cleanup({ comments: "jsdoc" }), + json() ] }, { @@ -44,7 +46,8 @@ export default [ declaration: false, declarationDir: undefined }), - cleanup({ comments: "jsdoc" }) + cleanup({ comments: "jsdoc" }), + json() ] } ] diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 64632e2f6..2d338de67 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,6 +1,6 @@ import * as constants from "./constants" import decodeMessage from "./decode-message" -import supportedNetworks from "./supported-networks" +export * from "./networks" export * from "./types" -export { constants, decodeMessage, supportedNetworks } +export { constants, decodeMessage } diff --git a/packages/utils/src/networks.ts b/packages/utils/src/networks.ts new file mode 100644 index 000000000..80636a6ad --- /dev/null +++ b/packages/utils/src/networks.ts @@ -0,0 +1,25 @@ +// eslint-disable-next-line import/no-relative-packages +import deployedContracts from "../../contracts/deployed-contracts.json" +import { SupportedNetwork } from "./types" + +// List of Semaphore supported networks. +const supportedNetworks: SupportedNetwork[] = ["sepolia", "mumbai", "optimism-sepolia", "arbitrum-sepolia", "arbitrum"] + +// Default Semaphore network. +const defaultNetwork: SupportedNetwork = "sepolia" + +export function getDeployedContract(supportedNetwork: SupportedNetwork) { + const deployedContract = deployedContracts.find(({ network }) => network === supportedNetwork) + + if (!deployedContract) { + throw new Error(`Semaphore has not been deployed on '${supportedNetwork}' yet`) + } + + return deployedContract.contracts.find(({ name }) => name === "Semaphore") as { + name: string + address: string + startBlock: number + } +} + +export { defaultNetwork, deployedContracts, supportedNetworks } diff --git a/packages/utils/src/supported-networks.ts b/packages/utils/src/supported-networks.ts deleted file mode 100644 index 3e487d98b..000000000 --- a/packages/utils/src/supported-networks.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { SupportedNetwork } from "./types" - -// List of Semaphore supported networks. -const supportedNetwork: SupportedNetwork[] = ["sepolia", "mumbai", "optimism-sepolia", "arbitrum-sepolia", "arbitrum"] - -export default supportedNetwork diff --git a/packages/utils/tests/index.test.ts b/packages/utils/tests/index.test.ts index 2a5c29071..580545831 100644 --- a/packages/utils/tests/index.test.ts +++ b/packages/utils/tests/index.test.ts @@ -1,7 +1,7 @@ import { encodeBytes32String } from "ethers/abi" import { toBigInt } from "ethers/utils" -import { supportedNetworks } from "../src" import decodeMessage from "../src/decode-message" +import { getDeployedContract, supportedNetworks } from "../src/networks" describe("Utils", () => { describe("# supportedNetworks", () => { @@ -11,6 +11,15 @@ describe("Utils", () => { }) }) + describe("# getDeployedContract", () => { + it("Should return Semaphore deployment data for Sepolia", () => { + const { address, startBlock } = getDeployedContract("sepolia") + + expect(address).toHaveLength(42) + expect(typeof startBlock).toBe("number") + }) + }) + describe("# decodeMessage", () => { it("Should decode a text message previously encoded to 32-byte bigint", () => { const message = "Hello World" diff --git a/yarn.lock b/yarn.lock index 0b544179e..651dc3d4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6597,6 +6597,7 @@ __metadata: dependencies: "@rollup/plugin-json": "npm:^6.1.0" "@rollup/plugin-typescript": "npm:^11.1.6" + "@semaphore-protocol/utils": "npm:4.0.0-beta.4" axios: "npm:1.6.6" ethers: "npm:6.11.0" rimraf: "npm:^5.0.5" @@ -6696,6 +6697,7 @@ __metadata: version: 0.0.0-use.local resolution: "@semaphore-protocol/utils@workspace:packages/utils" dependencies: + "@rollup/plugin-json": "npm:^6.1.0" "@rollup/plugin-typescript": "npm:^11.1.6" ethers: "npm:^6.11.1" rimraf: "npm:^5.0.5" @@ -25006,6 +25008,7 @@ __metadata: "@nomicfoundation/hardhat-verify": "npm:^2.0.0" "@openzeppelin/hardhat-upgrades": "npm:^3.0.4" "@semaphore-protocol/core": "workspace:packages/core" + "@semaphore-protocol/utils": "workspace:packages/utils" "@typechain/ethers-v6": "npm:^0.5.0" "@typechain/hardhat": "npm:^9.0.0" "@types/chai": "npm:^4.2.0" @@ -25035,6 +25038,7 @@ __metadata: "@docusaurus/preset-classic": "npm:3.1.1" "@docusaurus/tsconfig": "npm:3.1.1" "@mdx-js/react": "npm:^3.0.0" + "@semaphore-protocol/utils": "npm:4.0.0-beta.4" "@svgr/webpack": "npm:^5.5.0" "@types/react": "npm:^18.2.29" clsx: "npm:^1.2.1"