Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(contracts): fix contract extensions #16

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/contracts/contracts/SemaphoreVoting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ contract SemaphoreVoting is ISemaphoreVoting {

/// @dev See {ISemaphoreVoting-endPoll}.
function endPoll(uint256 pollId, uint256 decryptionKey) public override onlyCoordinator(pollId) {
if (polls[pollId].state != PollState.Ongoing) {
revert SemaphoreVoting__PollIsNotOngoing();
}

polls[pollId].state = PollState.Ended;

emit PollEnded(pollId, msg.sender, decryptionKey);
Expand Down
8 changes: 4 additions & 4 deletions packages/contracts/contracts/SemaphoreWhistleblowing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing {
}

/// @dev See {ISemaphoreWhistleblowing-createEntity}.
function createEntity(address editor) external {
uint256 groupId = semaphore.createGroup(editor);
function createEntity(address editor) external override {
uint256 groupId = semaphore.createGroup();
entities[groupId] = editor;
emit EntityCreated(groupId, editor);
}
Expand All @@ -46,7 +46,7 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing {
uint256 entityId,
uint256 identityCommitment,
uint256[] calldata proofSiblings
) external onlyEditor(entityId) {
) external override onlyEditor(entityId) {
semaphore.removeMember(entityId, identityCommitment, proofSiblings);
}

Expand All @@ -58,7 +58,7 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing {
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256[8] calldata proof
) external {
) external override {
ISemaphore.SemaphoreProof memory semaphoreProof = ISemaphore.SemaphoreProof({
merkleTreeDepth: merkleTreeDepth,
merkleTreeRoot: merkleTreeRoot,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@ interface ISemaphoreWhistleblowing {
/// @param entityId: Id of the entity.
/// @param identityCommitment: Identity commitment of the group member.
/// @param proofSiblings: Array of the sibling nodes of the proof of membership.
/// @param proofPathIndices: Path of the proof of membership.
function removeWhistleblower(
uint256 entityId,
uint256 identityCommitment,
uint256[] calldata proofSiblings,
uint8[] calldata proofPathIndices
uint256[] calldata proofSiblings
) external;

/// @dev Allows whistleblowers to publish leaks anonymously.
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "dotenv/config"
import { HardhatUserConfig } from "hardhat/config"
import "./tasks/deploy-semaphore-voting"
import "./tasks/deploy-semaphore-whistle-blowing"
import "./tasks/accounts"

const config: HardhatUserConfig = {
solidity: "0.8.23",
Expand Down
10 changes: 6 additions & 4 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"deploy:semaphore-whistleblowing": "hardhat deploy:semaphore-whistleblowing",
"verify": "hardhat verify",
"test": "hardhat test",
"test:report-gas": "REPORT_GAS=true hardhat test",
"test:coverage": "hardhat coverage",
"lint": "solhint 'contracts/**/*.sol'"
},
"devDependencies": {
Expand All @@ -19,9 +21,9 @@
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@semaphore-protocol/core": "4.0.0-beta.16",
"@semaphore-protocol/hardhat": "4.0.0-beta.16",
"@semaphore-protocol/utils": "4.0.0-beta.16",
"@semaphore-protocol/core": "4.0.1",
"@semaphore-protocol/hardhat": "4.0.1",
"@semaphore-protocol/utils": "4.0.1",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"@types/chai": "^4.2.0",
Expand All @@ -43,7 +45,7 @@
"hardhat-gas-reporter": "^1.0.8",
"prettier": "^3.2.5",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^4.1.1",
"solhint": "^5.0.3",
"solidity-coverage": "^0.8.1",
"ts-node": "^10.9.2",
"typechain": "^8.3.0",
Expand Down
154 changes: 123 additions & 31 deletions packages/contracts/test/SemaphoreVoting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import { ethers, run } from "hardhat"
import { Signer } from "ethers"
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
import { Group, Identity, generateProof } from "@semaphore-protocol/core"
import { BigNumber } from "@ethersproject/bignumber"
// @ts-ignore
import { SemaphoreVoting } from "../typechain-types"

describe("SemaphoreVoting", () => {
async function deploySemaphoreVotingFixture() {
const semaphoreVoting = await run("deploy:semaphore-voting", {
const { semaphore } = await run("deploy:semaphore", {
logs: false
})

const semaphoreVoting = await run("deploy:semaphore-voting", {
logs: false,
semaphore: await semaphore.getAddress()
})

const semaphoreContract = semaphore

const SemaphoreVotingContract: SemaphoreVoting = semaphoreVoting

const accounts = await run("accounts", { logs: false })
Expand All @@ -21,21 +27,30 @@ describe("SemaphoreVoting", () => {
const coordinator = accounts[0]
const voter = accounts[1]
const identity = new Identity()
const groupId = BigNumber.from(0)
const group = new Group(groupId)
const group = new Group()
group.addMember(identity.commitment)
const vote = ethers.keccak256(ethers.toUtf8Bytes("vote"))
const proof = await generateProof(identity, group, 0, vote)

return { SemaphoreVotingContract, coordinator, voter, identity, group, vote, proof, accountAddresses }
const proof = await generateProof(identity, group, vote, 0)

return {
SemaphoreVotingContract,
coordinator,
voter,
identity,
group,
vote,
proof,
accountAddresses,
semaphoreContract
}
}

describe("# createPoll", () => {
it("Should create a poll", async () => {
const { SemaphoreVotingContract, coordinator } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
const transaction = await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
const transaction = await SemaphoreVotingContract.createPoll(coordinator.address)

await expect(transaction)
.to.emit(SemaphoreVotingContract, "PollCreated")
Expand All @@ -45,28 +60,46 @@ describe("SemaphoreVoting", () => {

describe("# addVoter", () => {
it("Should add a voter to a poll", async () => {
const { SemaphoreVotingContract, coordinator, identity } = await loadFixture(deploySemaphoreVotingFixture)
const { SemaphoreVotingContract, coordinator, identity, group, semaphoreContract } =
await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)

const transaction = await SemaphoreVotingContract.addVoter(pollId, identity.commitment)

await expect(transaction).to.emit(SemaphoreVotingContract, "MemberAdded")
await expect(transaction)
.to.emit(semaphoreContract, "MemberAdded")
.withArgs(pollId, 0, identity.commitment, group.root)
})

it("Should not add a voter to a poll that has already been started", async () => {
const { SemaphoreVotingContract, coordinator, identity } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.startPoll(pollId, 0)

const transaction = SemaphoreVotingContract.addVoter(pollId, identity.commitment)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"Semaphore__PollHasAlreadyBeenStarted"
"SemaphoreVoting__PollHasAlreadyBeenStarted"
)
})

it("Should not add a voter to a poll if the coordinator is not correct", async () => {
const { SemaphoreVotingContract, coordinator, identity, voter } =
await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(coordinator.address)

const transaction = SemaphoreVotingContract.connect(voter).addVoter(pollId, identity.commitment)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"SemaphoreVoting__CallerIsNotThePollCoordinator"
)
})
})
Expand All @@ -76,7 +109,7 @@ describe("SemaphoreVoting", () => {
const { SemaphoreVotingContract, coordinator } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)

const transaction = await SemaphoreVotingContract.startPoll(pollId, 0)

Expand All @@ -87,62 +120,106 @@ describe("SemaphoreVoting", () => {
const { SemaphoreVotingContract, coordinator } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.startPoll(pollId, 0)

const transaction = SemaphoreVotingContract.startPoll(pollId, 0)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"Semaphore__PollHasAlreadyBeenStarted"
"SemaphoreVoting__PollHasAlreadyBeenStarted"
)
})

it("Should not start a poll if the caller is not poll coordinator", async () => {
const { SemaphoreVotingContract, voter } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(voter.address)
const transaction = SemaphoreVotingContract.startPoll(pollId, 0)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"SemaphoreVoting__CallerIsNotThePollCoordinator"
)
})
})

describe("# castVote", () => {
it("Should allow a voter to cast a vote", async () => {
const { SemaphoreVotingContract, coordinator, identity, vote, proof } =
const { SemaphoreVotingContract, coordinator, identity, vote, proof, group } =
await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.addVoter(pollId, identity.commitment)
await SemaphoreVotingContract.startPoll(pollId, 0)

const transaction = await SemaphoreVotingContract.castVote(vote, proof.nullifier, pollId, proof.proof)
const transaction = await SemaphoreVotingContract.castVote(
vote,
pollId,
proof.merkleTreeDepth,
proof.nullifier,
group.root,
proof.points
)

await expect(transaction).to.emit(SemaphoreVotingContract, "VoteAdded")
})

it("Should not allow a voter to cast a vote twice", async () => {
const { SemaphoreVotingContract, coordinator, identity, vote, proof } =
const { SemaphoreVotingContract, coordinator, identity, vote, proof, group, semaphoreContract } =
await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.addVoter(pollId, identity.commitment)
await SemaphoreVotingContract.startPoll(pollId, 0)
await SemaphoreVotingContract.castVote(vote, proof.nullifier, pollId, proof.proof)
await SemaphoreVotingContract.castVote(
vote,
pollId,
proof.merkleTreeDepth,
proof.nullifier,
group.root,
proof.points
)

const transaction = SemaphoreVotingContract.castVote(vote, proof.nullifier, pollId, proof.proof)
const transaction = SemaphoreVotingContract.castVote(
vote,
pollId,
group.depth,
proof.nullifier,
group.root,
proof.points
)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
semaphoreContract,
"Semaphore__YouAreUsingTheSameNullifierTwice"
)
})

it("Should not allow a voter to cast a vote in a poll that is not ongoing", async () => {
const { SemaphoreVotingContract, coordinator, identity, vote, proof } =
const { SemaphoreVotingContract, coordinator, identity, vote, proof, group } =
await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.addVoter(pollId, identity.commitment)

const transaction = SemaphoreVotingContract.castVote(vote, proof.nullifier, pollId, proof.proof)
const transaction = SemaphoreVotingContract.castVote(
vote,
pollId,
group.depth,
proof.nullifier,
group.root,
proof.points
)

await expect(transaction).to.be.revertedWithCustomError(SemaphoreVoting, "Semaphore__PollIsNotOngoing")
await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"SemaphoreVoting__PollIsNotOngoing"
)
})
})

Expand All @@ -151,7 +228,7 @@ describe("SemaphoreVoting", () => {
const { SemaphoreVotingContract, coordinator } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.startPoll(pollId, 0)

const transaction = await SemaphoreVotingContract.endPoll(pollId, 0)
Expand All @@ -163,13 +240,28 @@ describe("SemaphoreVoting", () => {
const { SemaphoreVotingContract, coordinator } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(pollId, coordinator.address)
await SemaphoreVotingContract.createPoll(coordinator.address)

const transaction = SemaphoreVotingContract.endPoll(pollId, 0)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"Semaphore__PollIsNotOngoing"
"SemaphoreVoting__PollIsNotOngoing"
)
})

it("Should not end a poll if the coordinator is not correct", async () => {
const { SemaphoreVotingContract, coordinator, voter } = await loadFixture(deploySemaphoreVotingFixture)

const pollId = 0
await SemaphoreVotingContract.createPoll(coordinator.address)
await SemaphoreVotingContract.startPoll(pollId, 0)

const transaction = SemaphoreVotingContract.connect(voter).endPoll(pollId, 0)

await expect(transaction).to.be.revertedWithCustomError(
SemaphoreVotingContract,
"SemaphoreVoting__CallerIsNotThePollCoordinator"
)
})
})
Expand Down
Loading