From ff3263d166b68cb35ae66ad49d9ce1e999ce443a Mon Sep 17 00:00:00 2001 From: cedoor Date: Mon, 25 Mar 2024 11:43:17 +0000 Subject: [PATCH] refactor(utils): re-organize 'networks' module structure and add tests re #715 --- jest.config.ts | 4 +- packages/cli/rollup.config.ts | 2 +- packages/contracts/scripts/utils.ts | 2 +- packages/data/rollup.config.ts | 8 ++- packages/data/src/ethers.ts | 8 ++- packages/data/src/subgraph.ts | 3 +- packages/proof/rollup.browser.config.ts | 3 +- packages/proof/rollup.node.config.ts | 3 +- packages/utils/package.json | 6 +- packages/utils/rollup.config.ts | 2 + packages/utils/src/networks.ts | 71 ------------------- .../{ => networks}/deployed-contracts.json | 0 packages/utils/src/networks/index.ts | 66 +++++++++++++++++ .../utils/src/networks/supported-networks.ts | 26 +++++++ packages/utils/tests/index.test.ts | 48 +++++++++---- 15 files changed, 155 insertions(+), 97 deletions(-) delete mode 100644 packages/utils/src/networks.ts rename packages/utils/src/{ => networks}/deployed-contracts.json (100%) create mode 100644 packages/utils/src/networks/index.ts create mode 100644 packages/utils/src/networks/supported-networks.ts diff --git a/jest.config.ts b/jest.config.ts index d4db960fe..af72ecac3 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -13,8 +13,8 @@ const projects: any = fs displayName: name, setupFiles: ["dotenv/config"], moduleNameMapper: { - "@semaphore-protocol/(.*)/(.*)": "/../$1/src/$2.ts", - "@semaphore-protocol/(.*)": "/../$1/src/index.ts" + "@semaphore-protocol/(.*)/(.*)": "/../$1/src/$2", + "@semaphore-protocol/(.*)": "/../$1/src" } })) diff --git a/packages/cli/rollup.config.ts b/packages/cli/rollup.config.ts index 6b89153b1..7188c6eb4 100644 --- a/packages/cli/rollup.config.ts +++ b/packages/cli/rollup.config.ts @@ -24,7 +24,7 @@ export default { "fs", "path", "child_process", - "@semaphore-protocol/utils/supported-networks" + "@semaphore-protocol/utils/networks" ], plugins: [ typescript({ diff --git a/packages/contracts/scripts/utils.ts b/packages/contracts/scripts/utils.ts index 6f4838d27..a870b6684 100644 --- a/packages/contracts/scripts/utils.ts +++ b/packages/contracts/scripts/utils.ts @@ -12,7 +12,7 @@ export type DeployedContracts = { contracts: NetworkDeployedContracts }[] -const deployedContractsPath = "../utils/src/deployed-contracts.json" +const deployedContractsPath = "../utils/src/networks/deployed-contracts.json" export function getDeployedContracts(): DeployedContracts { return JSON.parse(readFileSync(deployedContractsPath, "utf8")) diff --git a/packages/data/rollup.config.ts b/packages/data/rollup.config.ts index 412910a56..a78efe55c 100644 --- a/packages/data/rollup.config.ts +++ b/packages/data/rollup.config.ts @@ -19,6 +19,12 @@ export default { { file: pkg.exports.require, format: "cjs", banner, exports: "auto" }, { file: pkg.exports.default, format: "es", banner } ], - external: [...Object.keys(pkg.dependencies), "ethers/contract", "ethers/constants", "ethers/providers"], + external: [ + ...Object.keys(pkg.dependencies), + "ethers/contract", + "ethers/constants", + "ethers/providers", + "@semaphore-protocol/utils/networks" + ], plugins: [json(), typescript({ tsconfig: "./build.tsconfig.json" }), cleanup({ comments: "jsdoc" })] } diff --git a/packages/data/src/ethers.ts b/packages/data/src/ethers.ts index a5272860a..b5af82726 100644 --- a/packages/data/src/ethers.ts +++ b/packages/data/src/ethers.ts @@ -1,5 +1,9 @@ -import { SupportedNetwork, getDeployedContract, isSupportedNetwork } from "@semaphore-protocol/utils" -import { defaultNetwork } from "@semaphore-protocol/utils/networks" +import { + SupportedNetwork, + defaultNetwork, + getDeployedContract, + isSupportedNetwork +} from "@semaphore-protocol/utils/networks" import { ZeroAddress } from "ethers/constants" import { Contract } from "ethers/contract" import { diff --git a/packages/data/src/subgraph.ts b/packages/data/src/subgraph.ts index 50ac12b88..8ea5f525f 100644 --- a/packages/data/src/subgraph.ts +++ b/packages/data/src/subgraph.ts @@ -1,5 +1,4 @@ -import type { SupportedNetwork } from "@semaphore-protocol/utils" -import { defaultNetwork } from "@semaphore-protocol/utils/networks" +import { defaultNetwork, SupportedNetwork } from "@semaphore-protocol/utils/networks" import { AxiosRequestConfig } from "axios" import checkParameter from "./checkParameter" import getURL from "./getURL" diff --git a/packages/proof/rollup.browser.config.ts b/packages/proof/rollup.browser.config.ts index f473a391a..8d7524663 100644 --- a/packages/proof/rollup.browser.config.ts +++ b/packages/proof/rollup.browser.config.ts @@ -35,7 +35,8 @@ export default { "ethers/utils", "ethers/abi", "@zk-kit/utils/error-handlers", - "@zk-kit/utils/proof-packing" + "@zk-kit/utils/proof-packing", + "@semaphore-protocol/utils/constants" ], plugins: [ alias({ diff --git a/packages/proof/rollup.node.config.ts b/packages/proof/rollup.node.config.ts index 88b08d4ae..572f9349b 100644 --- a/packages/proof/rollup.node.config.ts +++ b/packages/proof/rollup.node.config.ts @@ -40,7 +40,8 @@ export default { "ethers/utils", "ethers/abi", "@zk-kit/utils/error-handlers", - "@zk-kit/utils/proof-packing" + "@zk-kit/utils/proof-packing", + "@semaphore-protocol/utils/constants" ], plugins: [ typescript({ diff --git a/packages/utils/package.json b/packages/utils/package.json index 692deaf99..99b115111 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -13,9 +13,9 @@ "default": "./dist/index.js" }, "./networks": { - "types": "./dist/types/networks.d.ts", - "require": "./dist/lib.commonjs/networks.cjs", - "default": "./dist/lib.esm/networks.js" + "types": "./dist/types/networks/index.d.ts", + "require": "./dist/lib.commonjs/networks/index.cjs", + "default": "./dist/lib.esm/networks/index.js" }, "./constants": { "types": "./dist/types/constants.d.ts", diff --git a/packages/utils/rollup.config.ts b/packages/utils/rollup.config.ts index ed43a444c..4ddc12cd9 100644 --- a/packages/utils/rollup.config.ts +++ b/packages/utils/rollup.config.ts @@ -20,6 +20,7 @@ export default [ { file: pkg.exports["."].require, format: "cjs", banner, exports: "auto" }, { file: pkg.exports["."].default, format: "es", banner } ], + external: [...Object.keys(pkg.dependencies), "ethers/abi", "ethers/utils"], plugins: [ typescript({ tsconfig: "./build.tsconfig.json" @@ -40,6 +41,7 @@ export default [ }, { dir: "./dist/lib.esm", format: "es", banner, preserveModules: true } ], + external: [...Object.keys(pkg.dependencies), "ethers/abi", "ethers/utils"], plugins: [ typescript({ tsconfig: "./build.tsconfig.json", diff --git a/packages/utils/src/networks.ts b/packages/utils/src/networks.ts deleted file mode 100644 index cb2f0aefc..000000000 --- a/packages/utils/src/networks.ts +++ /dev/null @@ -1,71 +0,0 @@ -import deployedContracts from "./deployed-contracts.json" - -// List of Semaphore supported networks. -export const supportedNetworks = { - sepolia: { - name: "Sepolia", - url: "https://rpc2.sepolia.org", - chainId: 11155111, - explorer: "https://sepolia.etherscan.io" - }, - "arbitrum-sepolia": { - name: "Arbitrum Sepolia", - url: "https://sepolia-rollup.arbitrum.io/rpc", - chainId: 421614, - explorer: "https://sepolia.arbiscan.io" - }, - "optimism-sepolia": { - name: "Optimism Sepolia", - url: "https://sepolia.optimism.io", - chainId: 11155420, - explorer: "https://sepolia-optimism.etherscan.io" - }, - "matic-mumbai": { - name: "Matic Mumbai", - url: "https://rpc-mumbai.polygon.technology", - chainId: 80001, - explorer: "https://mumbai.polygonscan.com" - } - // "arbitrum" -} - -export type SupportedNetwork = keyof typeof supportedNetworks - -// Default Semaphore network. -export const defaultNetwork: SupportedNetwork = "sepolia" - -export function isSupportedNetwork(supportedNetwork: string): boolean { - return Object.keys(supportedNetworks).includes(supportedNetwork) -} - -export function getHardhatNetworks(account?: string) { - if (!account) { - return {} - } - - const supportedNetworks2 = JSON.parse(JSON.stringify(supportedNetworks)) - - for (const key in supportedNetworks2) { - if (Object.prototype.hasOwnProperty.call(supportedNetworks2, key)) { - supportedNetworks2[key].accounts = [`0x${account}`] - } - } - - return supportedNetworks2 -} - -export function getDeployedContract(supportedNetwork: SupportedNetwork) { - if (!isSupportedNetwork(supportedNetwork)) { - throw new Error(`Semaphore has not been deployed on '${supportedNetwork}' yet`) - } - - const deployedContract = deployedContracts.find(({ network }) => network === supportedNetwork) - - return deployedContract!.contracts.find(({ name }) => name === "Semaphore") as { - name: string - address: string - startBlock: number - } -} - -export { deployedContracts } diff --git a/packages/utils/src/deployed-contracts.json b/packages/utils/src/networks/deployed-contracts.json similarity index 100% rename from packages/utils/src/deployed-contracts.json rename to packages/utils/src/networks/deployed-contracts.json diff --git a/packages/utils/src/networks/index.ts b/packages/utils/src/networks/index.ts new file mode 100644 index 000000000..395c539b7 --- /dev/null +++ b/packages/utils/src/networks/index.ts @@ -0,0 +1,66 @@ +/** + * @module Networks + * This module provides a collection of utility functions to provide the other internal + * packages and developers with information on deployed contracts and networks supported + * by Semaphore. + */ + +import deployedContracts from "./deployed-contracts.json" +import supportedNetworks from "./supported-networks" + +export type SupportedNetwork = keyof typeof supportedNetworks + +// Default Semaphore network. +export const defaultNetwork: SupportedNetwork = "sepolia" + +/** + * Returns true if a network is supported by Semaphore, false otherwise. + * @param supportedNetwork The network to be checked. + */ +export function isSupportedNetwork(supportedNetwork: string): boolean { + return Object.keys(supportedNetworks).includes(supportedNetwork) +} + +/** + * Utility function to get an object compatible with the Hardhat 'networks' option. + * If the private key is not defined it returns an empty object. + * @param privateKey Private key to be used with networks. + * @returns An object compatible with the Hardhat 'networks' option. + */ +export function getHardhatNetworks(privateKey?: string) { + if (!privateKey) { + return {} + } + + const supportedNetworksCopy = JSON.parse(JSON.stringify(supportedNetworks)) + + for (const key in supportedNetworksCopy) { + if (Object.prototype.hasOwnProperty.call(supportedNetworksCopy, key)) { + supportedNetworksCopy[key].accounts = [`0x${privateKey}`] + } + } + + return supportedNetworksCopy +} + +/** + * Returns name, address and start block of a Semaphore contract deployed + * on a specific supported network. + * @param The network supported by Semaphore. + * @returns An object with name, address and start block of the deployed contract. + */ +export function getDeployedContract(supportedNetwork: SupportedNetwork) { + if (!isSupportedNetwork(supportedNetwork)) { + throw new Error(`Semaphore has not been deployed on '${supportedNetwork}' yet`) + } + + const deployedContract = deployedContracts.find(({ network }) => network === supportedNetwork) + + return deployedContract!.contracts.find(({ name }) => name === "Semaphore") as { + name: string + address: string + startBlock: number + } +} + +export { deployedContracts, supportedNetworks } diff --git a/packages/utils/src/networks/supported-networks.ts b/packages/utils/src/networks/supported-networks.ts new file mode 100644 index 000000000..2805ab72d --- /dev/null +++ b/packages/utils/src/networks/supported-networks.ts @@ -0,0 +1,26 @@ +export default { + sepolia: { + name: "Sepolia", + url: "https://rpc2.sepolia.org", + chainId: 11155111, + explorer: "https://sepolia.etherscan.io" + }, + "arbitrum-sepolia": { + name: "Arbitrum Sepolia", + url: "https://sepolia-rollup.arbitrum.io/rpc", + chainId: 421614, + explorer: "https://sepolia.arbiscan.io" + }, + "optimism-sepolia": { + name: "Optimism Sepolia", + url: "https://sepolia.optimism.io", + chainId: 11155420, + explorer: "https://sepolia-optimism.etherscan.io" + }, + "matic-mumbai": { + name: "Matic Mumbai", + url: "https://rpc-mumbai.polygon.technology", + chainId: 80001, + explorer: "https://mumbai.polygonscan.com" + } +} diff --git a/packages/utils/tests/index.test.ts b/packages/utils/tests/index.test.ts index 14e393948..40029920e 100644 --- a/packages/utils/tests/index.test.ts +++ b/packages/utils/tests/index.test.ts @@ -1,25 +1,49 @@ import { encodeBytes32String } from "ethers/abi" import { toBigInt } from "ethers/utils" import decodeMessage from "../src/decode-message" -import { getDeployedContract, isSupportedNetwork } from "../src/networks" +import { getDeployedContract, getHardhatNetworks, isSupportedNetwork, supportedNetworks } from "../src/networks" describe("Utils", () => { - describe("# isSupportedNetwork", () => { - it("Should return true if the network is supported", () => { - expect(isSupportedNetwork("sepolia")).toBeTruthy() + describe("# networks", () => { + describe("# isSupportedNetwork", () => { + it("Should return true if the network is supported", () => { + expect(isSupportedNetwork("sepolia")).toBeTruthy() + }) + + it("Should return false if the network is not supported", () => { + expect(isSupportedNetwork("hello")).toBeFalsy() + }) }) - it("Should return false if the network is not supported", () => { - expect(isSupportedNetwork("hello")).toBeFalsy() + describe("# getDeployedContract", () => { + it("Should return Semaphore deployment data for Sepolia", () => { + const { address, startBlock } = getDeployedContract("sepolia") + + expect(address).toHaveLength(42) + expect(typeof startBlock).toBe("number") + }) + + it("Should throw an error if the network is not supported", () => { + const fun = () => getDeployedContract("hello" as any) + + expect(fun).toThrow("Semaphore has not been deployed on 'hello' yet") + }) }) - }) - describe("# getDeployedContract", () => { - it("Should return Semaphore deployment data for Sepolia", () => { - const { address, startBlock } = getDeployedContract("sepolia") + describe("# getHardhatNetworks", () => { + it("Should return an empty object if the private key is not defined", () => { + const networks = getHardhatNetworks() + + expect(networks).toEqual({}) + }) + + it("Should return a list of networks compatible with the Hardhat 'networks' object", () => { + const networks = getHardhatNetworks("ec12f72ab17a2f14cf538a1a2455d6cd94ec99a90e8d8be591f987744b7b440f") - expect(address).toHaveLength(42) - expect(typeof startBlock).toBe("number") + expect(Object.keys(networks)).toEqual(Object.keys(supportedNetworks)) + expect(Object.keys(networks)).toHaveLength(Object.keys(supportedNetworks).length) + expect(networks.sepolia.accounts).toHaveLength(1) + }) }) })