From 75990e358b3ea66735abb34b31578cfb1850db3a Mon Sep 17 00:00:00 2001 From: jancris100 <73757410+jancris100@users.noreply.github.com> Date: Tue, 14 May 2024 09:23:24 -0600 Subject: [PATCH] [add]zk-kit/utils/ --- packages/circuits/circomkit.json | 2 +- packages/circuits/package.json | 2 +- packages/contracts/test/Semaphore.ts | 288 +++++++-------------------- packages/data/src/ethers.ts | 21 +- packages/data/src/subgraph.ts | 63 +++--- packages/data/tests/ethers.test.ts | 24 +-- packages/proof/tests/index.test.ts | 24 --- 7 files changed, 122 insertions(+), 302 deletions(-) diff --git a/packages/circuits/circomkit.json b/packages/circuits/circomkit.json index f4d4553b6..d6de9534e 100644 --- a/packages/circuits/circomkit.json +++ b/packages/circuits/circomkit.json @@ -9,7 +9,7 @@ "dirBuild": "./build", "optimization": 2, "inspect": true, - "include": ["../../node_modules/circomlib/circuits", "../../node_modules/@zk-kit/binary-merkle-root.circom/src"], + "include": ["../../node_modules/circomlib/circuits", "../../node_modules/@zk-kit/circuits/circom"], "groth16numContributions": 1, "groth16askForEntropy": false, "logLevel": "INFO", diff --git a/packages/circuits/package.json b/packages/circuits/package.json index e8a5f993f..577a4c5a1 100644 --- a/packages/circuits/package.json +++ b/packages/circuits/package.json @@ -24,7 +24,7 @@ "access": "public" }, "dependencies": { - "@zk-kit/binary-merkle-root.circom": "1.0.0", + "@zk-kit/circuits": "0.2.4", "circomlib": "2.0.5" }, "devDependencies": { diff --git a/packages/contracts/test/Semaphore.ts b/packages/contracts/test/Semaphore.ts index c72619bc2..fd3c63f05 100644 --- a/packages/contracts/test/Semaphore.ts +++ b/packages/contracts/test/Semaphore.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable jest/valid-expect */ import { Group, Identity, SemaphoreProof, generateProof } from "@semaphore-protocol/core" -import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers" import { expect } from "chai" import { Signer, ZeroAddress } from "ethers" import { run } from "hardhat" @@ -9,30 +8,29 @@ import { run } from "hardhat" import { Semaphore } from "../typechain-types" describe("Semaphore", () => { - async function deploySemaphoreFixture() { + let semaphoreContract: Semaphore + let accounts: Signer[] + let accountAddresses: string[] + + const merkleTreeDepth = 12 + + const groupId = 0 + const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map(({ commitment }) => commitment) + + before(async () => { const { semaphore } = await run("deploy", { logs: false }) - const semaphoreContract: Semaphore = semaphore - - const accounts = await run("accounts", { logs: false }) - const accountAddresses = await Promise.all(accounts.map((signer: Signer) => signer.getAddress())) + semaphoreContract = semaphore - const groupId = 0 - - return { - semaphoreContract, - accounts, - accountAddresses, - groupId - } - } + accounts = await run("accounts", { logs: false }) + accountAddresses = await Promise.all(accounts.map((signer: Signer) => signer.getAddress())) + }) describe("# createGroup", () => { it("Should create a group", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - + const groupId = 0 const transaction = semaphoreContract.connect(accounts[1])["createGroup(address)"](accountAddresses[1]) await expect(transaction).to.emit(semaphoreContract, "GroupCreated").withArgs(groupId) @@ -42,16 +40,11 @@ describe("Semaphore", () => { }) it("Should create a group with a custom Merkle tree root expiration", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - + const groupId = 1 const transaction = await semaphoreContract.connect(accounts[1])["createGroup(address,uint256)"]( accountAddresses[0], 5 // 5 seconds. ) - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) - await semaphoreContract.addMember(groupId, members[0]) await semaphoreContract.addMember(groupId, members[1]) await semaphoreContract.addMember(groupId, members[2]) @@ -63,7 +56,7 @@ describe("Semaphore", () => { }) it("Should create a group without any parameters", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) + const groupId = 2 const transaction = await semaphoreContract["createGroup()"]() @@ -76,10 +69,6 @@ describe("Semaphore", () => { describe("# updateGroupMerkleTreeDuration", () => { it("Should not update a group Merkle tree duration if the caller is not the group admin", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[1]) - const transaction = semaphoreContract.updateGroupMerkleTreeDuration(groupId, 300) await expect(transaction).to.be.revertedWithCustomError( @@ -89,11 +78,7 @@ describe("Semaphore", () => { }) it("Should update the group Merkle tree duration", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - - const transaction = semaphoreContract.updateGroupMerkleTreeDuration(groupId, 300) + const transaction = semaphoreContract.connect(accounts[1]).updateGroupMerkleTreeDuration(groupId, 300) await expect(transaction) .to.emit(semaphoreContract, "GroupMerkleTreeDurationUpdated") @@ -103,10 +88,6 @@ describe("Semaphore", () => { describe("# updateGroupAdmin", () => { it("Should not update an admin if the caller is not the admin", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[1]) - const transaction = semaphoreContract.updateGroupAdmin(groupId, accountAddresses[0]) await expect(transaction).to.be.revertedWithCustomError( @@ -116,23 +97,14 @@ describe("Semaphore", () => { }) it("Should update the admin", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - - const transaction = semaphoreContract.updateGroupAdmin(groupId, accountAddresses[1]) + const transaction = semaphoreContract.connect(accounts[1]).updateGroupAdmin(groupId, accountAddresses[0]) await expect(transaction) .to.emit(semaphoreContract, "GroupAdminPending") - .withArgs(groupId, accountAddresses[0], accountAddresses[1]) + .withArgs(groupId, accountAddresses[1], accountAddresses[0]) }) it("Should not accept accept the new admin if the caller is not the new admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.updateGroupAdmin(groupId, accountAddresses[1]) - const transaction = semaphoreContract.connect(accounts[2]).acceptGroupAdmin(groupId) await expect(transaction).to.be.revertedWithCustomError( @@ -142,27 +114,18 @@ describe("Semaphore", () => { }) it("Should accept the new admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.updateGroupAdmin(groupId, accountAddresses[1]) - - const transaction = semaphoreContract.connect(accounts[1]).acceptGroupAdmin(groupId) + const transaction = semaphoreContract.acceptGroupAdmin(groupId) await expect(transaction) .to.emit(semaphoreContract, "GroupAdminUpdated") - .withArgs(groupId, accountAddresses[0], accountAddresses[1]) + .withArgs(groupId, accountAddresses[1], accountAddresses[0]) }) }) describe("# addMember", () => { it("Should not add a member if the caller is not the group admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - const member = 2n - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const transaction = semaphoreContract.connect(accounts[1]).addMember(groupId, member) await expect(transaction).to.be.revertedWithCustomError( @@ -172,17 +135,10 @@ describe("Semaphore", () => { }) it("Should add a new member in an existing group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - const group = new Group() - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) group.addMember(members[0]) - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const transaction = semaphoreContract.addMember(groupId, members[0]) await expect(transaction) @@ -193,12 +149,8 @@ describe("Semaphore", () => { describe("# addMembers", () => { it("Should not add members if the caller is not the group admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - const members = [1n, 2n, 3n] - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const transaction = semaphoreContract.connect(accounts[1]).addMembers(groupId, members) await expect(transaction).to.be.revertedWithCustomError( @@ -208,8 +160,7 @@ describe("Semaphore", () => { }) it("Should add new members to an existing group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - + const groupId = 3 const members = [1n, 2n, 3n] const group = new Group() @@ -227,12 +178,8 @@ describe("Semaphore", () => { describe("# updateMember", () => { it("Should not update a member if the caller is not the group admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - const member = 2n - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const transaction = semaphoreContract.connect(accounts[1]).updateMember(groupId, member, 1, [0, 1]) await expect(transaction).to.be.revertedWithCustomError( @@ -242,8 +189,7 @@ describe("Semaphore", () => { }) it("Should update a member from an existing group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - + const groupId = 4 const members = [1n, 2n, 3n] const group = new Group() @@ -264,12 +210,8 @@ describe("Semaphore", () => { describe("# removeMember", () => { it("Should not remove a member if the caller is not the group admin", async () => { - const { semaphoreContract, accounts, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - const member = 2n - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const transaction = semaphoreContract.connect(accounts[1]).removeMember(groupId, member, [0, 1]) await expect(transaction).to.be.revertedWithCustomError( @@ -279,8 +221,7 @@ describe("Semaphore", () => { }) it("Should remove a member from an existing group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - + const groupId = 5 const members = [1n, 2n, 3n] const group = new Group() @@ -301,18 +242,12 @@ describe("Semaphore", () => { describe("# getGroupAdmin", () => { it("Should return a 0 address if the group does not exist", async () => { - const { semaphoreContract } = await loadFixture(deploySemaphoreFixture) - const address = await semaphoreContract.getGroupAdmin(999) expect(address).to.equal(ZeroAddress) }) it("Should return the address of the group admin", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const address = await semaphoreContract.getGroupAdmin(groupId) expect(address).to.equal(accountAddresses[0]) @@ -320,45 +255,31 @@ describe("Semaphore", () => { }) describe("# verifyProof", () => { - async function deployVerifyProofFixture() { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) + const groupId = 6 + const message = 2 + const identity = new Identity("0") - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) + const group = new Group() - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMembers(groupId, members) + group.addMembers(members) - const identity = new Identity("0") - const group = new Group() + let proof: SemaphoreProof - group.addMembers(members) + before(async () => { + await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const merkleTreeDepth = 12 - const message = 2 - const proof: SemaphoreProof = await generateProof(identity, group, message, group.root, merkleTreeDepth) + await semaphoreContract.addMembers(groupId, members) - return { - semaphoreContract, - accountAddresses, - groupId, - members, - proof - } - } + proof = await generateProof(identity, group, message, group.root, merkleTreeDepth) + }) it("Should not verify a proof if the group does not exist", async () => { - const { semaphoreContract, proof } = await loadFixture(deployVerifyProofFixture) - const transaction = semaphoreContract.verifyProof(11, proof) await expect(transaction).to.be.revertedWithCustomError(semaphoreContract, "Semaphore__GroupDoesNotExist") }) it("Should not verify a proof if the Merkle tree root is not part of the group", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployVerifyProofFixture) - const transaction = semaphoreContract.verifyProof(groupId, { ...proof, merkleTreeRoot: 1 }) await expect(transaction).to.be.revertedWithCustomError( @@ -368,31 +289,20 @@ describe("Semaphore", () => { }) it("Should verify a proof for an onchain group", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployVerifyProofFixture) - const validProof = await semaphoreContract.verifyProof(groupId, proof) expect(validProof).to.equal(true) }) it("Should not verify a proof if the Merkle tree root is expired", async () => { - const { semaphoreContract, accountAddresses, members } = await loadFixture(deployVerifyProofFixture) - - // create new group with 0s Merkle tree root expiration const groupId = 1 - await semaphoreContract["createGroup(address,uint256)"](accountAddresses[0], 0) - await semaphoreContract.addMember(groupId, members[0]) - await semaphoreContract.addMember(groupId, members[1]) - await semaphoreContract.addMember(groupId, members[2]) - const message = 2 - const merkleTreeDepth = 12 - const identity = new Identity("0") const group = new Group() group.addMembers([members[0], members[1]]) const proof = await generateProof(identity, group, message, group.root, merkleTreeDepth) + const transaction = semaphoreContract.verifyProof(groupId, proof) await expect(transaction).to.be.revertedWithCustomError( @@ -402,16 +312,8 @@ describe("Semaphore", () => { }) it("Should not verify a proof if the Merkle depth is not supported", async () => { - const { semaphoreContract, groupId, members } = await loadFixture(deployVerifyProofFixture) - - const message = 2 - const merkleTreeDepth = 12 - const identity = new Identity("0") - const group = new Group() - - group.addMembers(members) - const scope = "random-scope" + const proof = await generateProof(identity, group, message, scope, merkleTreeDepth) proof.merkleTreeDepth = 33 @@ -425,11 +327,9 @@ describe("Semaphore", () => { }) it("Should not verify a proof if the group has no members", async () => { - const { semaphoreContract, accountAddresses, proof } = await loadFixture(deployVerifyProofFixture) - + const groupId = 7 await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const groupId = 1 const transaction = semaphoreContract.verifyProof(groupId, proof) await expect(transaction).to.be.revertedWithCustomError(semaphoreContract, "Semaphore__GroupHasNoMembers") @@ -437,64 +337,58 @@ describe("Semaphore", () => { }) describe("# validateProof", () => { - async function deployValidateProofFixture() { - const { semaphoreContract, accountAddresses } = await loadFixture(deploySemaphoreFixture) + const message = 2 + const identity = new Identity("0") + const groupOneMemberId = 7 - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) - const merkleTreeDepth = 12 - const message = 2 + const group = new Group() + const groupOneMember = new Group() - // groupId = 0 - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMembers(0, [members[1], members[2]]) + group.addMembers(members) + groupOneMember.addMember(members[0]) - // groupId = 1 - const groupId = 1 - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMember(groupId, members[0]) - await semaphoreContract.addMember(groupId, members[1]) + let proof: SemaphoreProof + let proofOneMember: SemaphoreProof - const identity = new Identity("0") - const group = new Group() - - group.addMember(members[0]) + before(async () => { + await semaphoreContract["createGroup(address)"](accountAddresses[0]) - const proof = await generateProof(identity, group, message, group.root, merkleTreeDepth) + await semaphoreContract.addMembers(groupId, [members[1], members[2]]) + await semaphoreContract.addMember(groupOneMemberId, members[0]) - return { semaphoreContract, groupId, proof } - } + proof = await generateProof(identity, group, message, group.root, merkleTreeDepth) + proofOneMember = await generateProof( + identity, + groupOneMember, + message, + groupOneMember.root, + merkleTreeDepth + ) + }) it("Should throw an exception if the proof is not valid", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployValidateProofFixture) - const transaction = semaphoreContract.validateProof(groupId, { ...proof, scope: 0 }) await expect(transaction).to.be.revertedWithCustomError(semaphoreContract, "Semaphore__InvalidProof") }) it("Should validate a proof for an onchain group with one member correctly", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployValidateProofFixture) - - const transaction = semaphoreContract.validateProof(groupId, proof) + const transaction = semaphoreContract.validateProof(groupOneMemberId, proofOneMember) await expect(transaction) .to.emit(semaphoreContract, "ProofValidated") .withArgs( - groupId, - proof.merkleTreeDepth, - proof.merkleTreeRoot, - proof.nullifier, - proof.message, - proof.merkleTreeRoot, - proof.points + groupOneMemberId, + proofOneMember.merkleTreeDepth, + proofOneMember.merkleTreeRoot, + proofOneMember.nullifier, + proofOneMember.message, + proofOneMember.merkleTreeRoot, + proofOneMember.points ) }) it("Should validate a proof for an onchain group with more than one member correctly", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployValidateProofFixture) - const transaction = semaphoreContract.validateProof(groupId, proof) await expect(transaction) @@ -511,10 +405,6 @@ describe("Semaphore", () => { }) it("Should not validate the same proof for an onchain group twice", async () => { - const { semaphoreContract, groupId, proof } = await loadFixture(deployValidateProofFixture) - - await semaphoreContract.validateProof(groupId, proof) - const transaction = semaphoreContract.validateProof(groupId, proof) await expect(transaction).to.be.revertedWithCustomError( @@ -527,62 +417,30 @@ describe("Semaphore", () => { describe("SemaphoreGroups", () => { describe("# hasMember", () => { it("Should return true because the member is part of the group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMember(groupId, members[0]) - + const groupId = 1 const isMember = await semaphoreContract.hasMember(groupId, members[0]) await expect(isMember).to.be.true }) - it("Should return false because the member is not part of the group", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - + const groupId = 1 const identity = new Identity() const isMember = await semaphoreContract.hasMember(groupId, identity.commitment) await expect(isMember).to.be.false }) }) - describe("# indexOf", () => { it("Should return the index of a member", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMember(groupId, members[0]) - + const groupId = 1 const index = await semaphoreContract.indexOf(groupId, members[0]) await expect(index).to.equal(0) }) }) - describe("# getMerkleTreeDepth", () => { it("Should return the merkle tree depth", async () => { - const { semaphoreContract, accountAddresses, groupId } = await loadFixture(deploySemaphoreFixture) - - const members = Array.from({ length: 3 }, (_, i) => new Identity(i.toString())).map( - ({ commitment }) => commitment - ) - - await semaphoreContract["createGroup(address)"](accountAddresses[0]) - await semaphoreContract.addMember(groupId, members[0]) - await semaphoreContract.addMember(groupId, members[1]) - await semaphoreContract.addMember(groupId, members[2]) - + const groupId = 1 const depth = await semaphoreContract.getMerkleTreeDepth(groupId) await expect(depth).to.equal(2) diff --git a/packages/data/src/ethers.ts b/packages/data/src/ethers.ts index 3acc20261..f9dd69391 100644 --- a/packages/data/src/ethers.ts +++ b/packages/data/src/ethers.ts @@ -16,6 +16,11 @@ import { PocketProvider, Provider } from "ethers/providers" +import { + requireObject, + requireDefined, + requireString +} from "@zk-kit/utils/error-handlers"; import checkParameter from "./checkParameter" import getEvents from "./getEvents" import SemaphoreABI from "./semaphoreABI.json" @@ -40,16 +45,16 @@ export default class SemaphoreEthers { * @param options Configuration options for the ethers provider and the Semaphore contract. */ constructor(networkOrEthereumURL: EthersNetwork | string = defaultNetwork, options: EthersOptions = {}) { - checkParameter(networkOrEthereumURL, "networkOrSubgraphURL", "string") + requireString(networkOrEthereumURL, "networkOrSubgraphURL"); if (options.provider) { - checkParameter(options.provider, "provider", "string") + requireString(options.provider, "provider"); } else if (!networkOrEthereumURL.startsWith("http")) { options.provider = "infura" } if (options.apiKey) { - checkParameter(options.apiKey, "apiKey", "string") + requireString(options.apiKey, "apiKey"); } if (isSupportedNetwork(networkOrEthereumURL)) { @@ -140,7 +145,7 @@ export default class SemaphoreEthers { * @returns A promise that resolves to a GroupResponse object. */ async getGroup(groupId: string): Promise { - checkParameter(groupId, "groupId", "string") + requireString(groupId, "groupId"); const groupAdmin = await this._contract.getGroupAdmin(groupId) @@ -172,7 +177,7 @@ export default class SemaphoreEthers { * @returns A promise that resolves to an array of member identity commitments as strings. */ async getGroupMembers(groupId: string): Promise { - checkParameter(groupId, "groupId", "string") + requireString(groupId, "groupId"); const groupAdmin = await this._contract.getGroupAdmin(groupId) @@ -257,7 +262,7 @@ export default class SemaphoreEthers { * @returns A promise that resolves to an array of validated proofs. */ async getGroupValidatedProofs(groupId: string): Promise { - checkParameter(groupId, "groupId", "string") + requireString(groupId, "groupId"); const groupAdmin = await this._contract.getGroupAdmin(groupId) @@ -290,8 +295,8 @@ export default class SemaphoreEthers { * @returns A promise that resolves to true if the member is part of the group, otherwise false. */ async isGroupMember(groupId: string, member: string): Promise { - checkParameter(groupId, "groupId", "string") - checkParameter(member, "member", "string") + requireString(groupId, "groupId"); + requireString(member, "member"); return this._contract.hasMember(groupId, member) } diff --git a/packages/data/src/subgraph.ts b/packages/data/src/subgraph.ts index 35a467f1e..ee4985595 100644 --- a/packages/data/src/subgraph.ts +++ b/packages/data/src/subgraph.ts @@ -1,5 +1,10 @@ import { defaultNetwork, SupportedNetwork } from "@semaphore-protocol/utils/networks" import { AxiosRequestConfig } from "axios" +import { + requireObject, + requireDefined, + requireString +} from "@zk-kit/utils/error-handlers"; import checkParameter from "./checkParameter" import getURL from "./getURL" import request from "./request" @@ -24,7 +29,7 @@ export default class SemaphoreSubgraph { * @param networkOrSubgraphURL Either a supported network identifier or a direct URL to the subgraph. */ constructor(networkOrSubgraphURL: SupportedNetwork | string = defaultNetwork) { - checkParameter(networkOrSubgraphURL, "networkOrSubgraphURL", "string") + requireString(networkOrSubgraphURL, "networkOrSubgraphURL"); if (typeof networkOrSubgraphURL === "string" && networkOrSubgraphURL.startsWith("http")) { this._url = networkOrSubgraphURL @@ -73,12 +78,12 @@ export default class SemaphoreSubgraph { * @returns A promise that resolves to an array of group details. */ async getGroups(options: GroupOptions = {}): Promise { - checkParameter(options, "options", "object") + requireObject(options, "options"); const { members = false, validatedProofs = false } = options - checkParameter(members, "members", "boolean") - checkParameter(validatedProofs, "validatedProofs", "boolean") + requireDefined(members, "members"); + requireDefined(validatedProofs, "validatedProofs"); let filtersQuery = "" @@ -120,16 +125,14 @@ export default class SemaphoreSubgraph { size } admin - ${ - members === true - ? `members(orderBy: index) { + ${members === true + ? `members(orderBy: index) { identityCommitment }` - : "" - } - ${ - validatedProofs === true - ? `validatedProofs(orderBy: timestamp) { + : "" + } + ${validatedProofs === true + ? `validatedProofs(orderBy: timestamp) { message merkleTreeRoot merkleTreeDepth @@ -138,8 +141,8 @@ export default class SemaphoreSubgraph { points timestamp }` - : "" - } + : "" + } } }` }) @@ -164,13 +167,14 @@ export default class SemaphoreSubgraph { * @returns A promise that resolves to the details of the specified group. */ async getGroup(groupId: string, options: Omit = {}): Promise { - checkParameter(groupId, "groupId", "string") - checkParameter(options, "options", "object") + + requireString(groupId, "groupId"); + requireObject(options, "options"); const { members = false, validatedProofs = false } = options - checkParameter(members, "members", "boolean") - checkParameter(validatedProofs, "validatedProofs", "boolean") + requireDefined(members, "members"); + requireDefined(validatedProofs, "validatedProofs"); const config: AxiosRequestConfig = { method: "post", @@ -184,16 +188,14 @@ export default class SemaphoreSubgraph { size } admin - ${ - members === true - ? `members(orderBy: index) { + ${members === true + ? `members(orderBy: index) { identityCommitment }` - : "" - } - ${ - validatedProofs === true - ? `validatedProofs(orderBy: timestamp) { + : "" + } + ${validatedProofs === true + ? `validatedProofs(orderBy: timestamp) { message merkleTreeRoot merkleTreeDepth @@ -202,8 +204,8 @@ export default class SemaphoreSubgraph { points timestamp }` - : "" - } + : "" + } } }` }) @@ -247,8 +249,9 @@ export default class SemaphoreSubgraph { * @returns A promise that resolves to true if the member is part of the group, otherwise false. */ async isGroupMember(groupId: string, member: string): Promise { - checkParameter(groupId, "groupId", "string") - checkParameter(member, "member", "string") + + requireString(groupId, "groupId"); + requireString(member, "member"); const config: AxiosRequestConfig = { method: "post", diff --git a/packages/data/tests/ethers.test.ts b/packages/data/tests/ethers.test.ts index 27c8fd19f..b124f1328 100644 --- a/packages/data/tests/ethers.test.ts +++ b/packages/data/tests/ethers.test.ts @@ -18,8 +18,7 @@ jest.mock("ethers/contract", () => ({ getMerkleTreeRoot: () => "222", getMerkleTreeDepth: () => BigInt(3), getMerkleTreeSize: () => BigInt(8), - getGroupAdmin: () => "0xA9C2B639a28cDa8b59C4377e980F75A93dD8605F", - hasMember: () => true + getGroupAdmin: () => "0xA9C2B639a28cDa8b59C4377e980F75A93dD8605F" }) as any ) })) @@ -236,25 +235,4 @@ describe("SemaphoreEthers", () => { await expect(fun).rejects.toThrow("Group '666' not found") }) }) - - describe("isGroupMember", () => { - it("Should return true because the member is part of the group", async () => { - const semaphore = new SemaphoreEthers() - - const isMember = await semaphore.isGroupMember("42", "1") - - expect(isMember).toBeTruthy() - }) - it("Should return false because the member is not part of the group", async () => { - ContractMocked.mockReturnValueOnce({ - hasMember: () => false - } as any) - - const semaphore = new SemaphoreEthers() - - const isMember = await semaphore.isGroupMember("48", "2") - - expect(isMember).toBeFalsy() - }) - }) }) diff --git a/packages/proof/tests/index.test.ts b/packages/proof/tests/index.test.ts index 192e2da71..c0f50f407 100644 --- a/packages/proof/tests/index.test.ts +++ b/packages/proof/tests/index.test.ts @@ -58,30 +58,6 @@ describe("Proof", () => { expect(typeof proof).toBe("object") expect(BigInt(proof.merkleTreeRoot)).toBe(group.root) }, 70000) - - it("Should generate a Semaphore proof without passing the tree depth", async () => { - const group = new Group([1n, 2n, identity.commitment]) - - proof = await generateProof(identity, group, message, scope) - - expect(typeof proof).toBe("object") - expect(BigInt(proof.merkleTreeRoot)).toBe(group.root) - }, 70000) - - it("Should throw an error because snarkArtifacts is not an object", async () => { - const group = new Group([1n, 2n, identity.commitment]) - const fun = () => generateProof(identity, group, message, scope, undefined, "hello" as any) - - await expect(fun).rejects.toThrow("is not an object") - }) - - it("Should throw an error because the message value is incorrect", async () => { - const group = new Group([1n, 2n, identity.commitment]) - - const fun = () => generateProof(identity, group, Number.MAX_VALUE, scope, treeDepth) - - await expect(fun).rejects.toThrow("overflow") - }) }) describe("# verifyProof", () => {