Skip to content

Commit 3ad17b1

Browse files
rin-stdamianmarti
andauthored
feat: zk-voting migration to hh v3 (#461)
* feat: migration to hh v3 * fix: configs, imports * Move libraries param on deployment script * fix: small issues * chore: bump create-eth 2.0.18 -> 2.0.20 --------- Co-authored-by: Damian <damianmarti@gmail.com>
1 parent 8668c62 commit 3ad17b1

16 files changed

Lines changed: 106 additions & 95 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ If you are using vscode you may want to install the [Noir Language Support](http
8989
Then download the challenge to your computer and install dependencies by running:
9090

9191
```sh
92-
npx create-eth@2.0.18 -e scaffold-eth/se-2-challenges:challenge-zk-voting challenge-zk-voting
92+
npx create-eth@2.0.20 -e scaffold-eth/se-2-challenges:challenge-zk-voting challenge-zk-voting
9393
cd challenge-zk-voting
9494
```
9595

extension/.ai/CHALLENGE.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ checkpoints:
328328
329329
Say **"check"** when you're ready!
330330
file: "packages/circuits/src/main.nr"
331-
test: "cd extension/packages/circuits && nargo check 2>&1 | grep -v warning && echo 'Circuit check passed!'"
331+
test: "cd packages/circuits && nargo check 2>&1 | grep -v warning && echo 'Circuit check passed!'"
332332
hints:
333333
- "`hash_1` takes an array of one element: `hash_1([nullifier])`. `hash_2` takes an array of two: `hash_2([nullifier, secret])`."
334334
- |
@@ -447,7 +447,7 @@ checkpoints:
447447
448448
Say **"check"** when you're ready!
449449
file: "packages/circuits/src/main.nr"
450-
test: "cd extension/packages/circuits && nargo check 2>&1 | grep -v warning && echo 'Circuit check passed!'"
450+
test: "cd packages/circuits && nargo check 2>&1 | grep -v warning && echo 'Circuit check passed!'"
451451
hints:
452452
- "Don't forget to uncomment BOTH the import at the top AND the function parameters. The parameters are commented out below the `////// Checkpoint 4 //////` comment in the function signature."
453453
- |
@@ -586,7 +586,7 @@ checkpoints:
586586
587587
Say **"check"** when you're ready!
588588
file: "packages/circuits/src/main.nr"
589-
test: "test -s extension/packages/circuits/target/Verifier.sol && grep -q 'function verify' extension/packages/circuits/target/Verifier.sol && echo 'Verifier contract generated!'"
589+
test: "test -s packages/circuits/target/Verifier.sol && grep -q 'function verify' packages/circuits/target/Verifier.sol && echo 'Verifier contract generated!'"
590590
hints:
591591
- "Make sure you `cd packages/circuits` first. All three commands must be run from that directory."
592592
- |
@@ -913,7 +913,7 @@ checkpoints:
913913
914914
Say **"check"** when you're ready!
915915
file: "packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx"
916-
test: "grep -q 'Fr.random' extension/packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx && grep -q 'poseidon2' extension/packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx && echo 'Commitment generation check passed!'"
916+
test: "grep -q 'Fr.random' packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx && grep -q 'poseidon2' packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx && echo 'Commitment generation check passed!'"
917917
hints:
918918
- "Cast `Fr.random()` to BigInt: `const nullifier = BigInt(Fr.random().toString());`. Use `toHex(value, { size: 32 })` for the hex conversion."
919919
- |
@@ -1083,7 +1083,7 @@ checkpoints:
10831083
10841084
Say **"check"** when you're ready!
10851085
file: "packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx"
1086-
test: "grep -q 'new Noir' extension/packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx && grep -q 'UltraHonkBackend' extension/packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx && echo 'Proof generation check passed!'"
1086+
test: "grep -q 'new Noir' packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx && grep -q 'UltraHonkBackend' packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx && echo 'Proof generation check passed!'"
10871087
hints:
10881088
- 'Events are emitted newest-last. Reverse the leaves array before inserting into the tree: `leaves.reverse()`. Pad siblings to 16 with `"0"`.'
10891089
- |
@@ -1247,7 +1247,7 @@ checkpoints:
12471247
12481248
Say **"check"** when you're ready!
12491249
file: "packages/nextjs/app/voting/_challengeComponents/VoteWithBurnerHardhat.tsx"
1250-
test: "grep -q 'generatePrivateKey' extension/packages/nextjs/app/voting/_challengeComponents/VoteWithBurnerHardhat.tsx && grep -q 'viemContract.write.vote' extension/packages/nextjs/app/voting/_challengeComponents/VoteWithBurnerHardhat.tsx && echo 'Burner wallet check passed!'"
1250+
test: "grep -q 'generatePrivateKey' packages/nextjs/app/voting/_challengeComponents/VoteWithBurnerHardhat.tsx && grep -q 'viemContract.write.vote' packages/nextjs/app/voting/_challengeComponents/VoteWithBurnerHardhat.tsx && echo 'Burner wallet check passed!'"
12511251
hints:
12521252
- "`generatePrivateKey()` from `viem/accounts` creates a random private key. `privateKeyToAccount(pk)` derives the address from it."
12531253
- |

extension/README.md.args.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ If you are using vscode you may want to install the [Noir Language Support](http
9494
Then download the challenge to your computer and install dependencies by running:
9595
9696
\`\`\`javascript
97-
npx create-eth@2.0.18 -e scaffold-eth/se-2-challenges:challenge-zk-voting challenge-zk-voting
97+
npx create-eth@2.0.20 -e scaffold-eth/se-2-challenges:challenge-zk-voting challenge-zk-voting
9898
cd challenge-zk-voting
9999
\`\`\`
100100

extension/packages/hardhat/contracts/Voting.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//SPDX-License-Identifier: MIT
22
pragma solidity >=0.8.0 <0.9.0;
33

4-
import {LeanIMT, LeanIMTData} from "@zk-kit/lean-imt.sol/LeanIMT.sol";
5-
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
4+
import { LeanIMT, LeanIMTData } from "@zk-kit/lean-imt.sol/LeanIMT.sol";
5+
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
66
/// Checkpoint 6 //////
77
// import {IVerifier} from "./Verifier.sol";
88

extension/packages/hardhat/contracts/mocks/VerifierMock.sol

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity >=0.8.0 <0.9.0;
33

44
/// Checkpoint 6 //////
5-
import {IVerifier} from "../Verifier.sol";
5+
import { IVerifier } from "../Verifier.sol";
66

77
contract VerifierMock is IVerifier {
88
bool public shouldVerify = true;
@@ -40,8 +40,11 @@ contract VerifierMock is IVerifier {
4040
}
4141
if (enforceExpectedInputs) {
4242
if (
43-
_publicInputs.length != 4 || _publicInputs[0] != expectedNullifier || _publicInputs[1] != expectedRoot
44-
|| _publicInputs[2] != expectedVote || _publicInputs[3] != expectedDepth
43+
_publicInputs.length != 4 ||
44+
_publicInputs[0] != expectedNullifier ||
45+
_publicInputs[1] != expectedRoot ||
46+
_publicInputs[2] != expectedVote ||
47+
_publicInputs[3] != expectedDepth
4548
) {
4649
return false;
4750
}
Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,68 @@
1-
import { HardhatRuntimeEnvironment } from "hardhat/types";
2-
import { DeployFunction } from "hardhat-deploy/types";
1+
import { artifacts, deployScript } from "../rocketh/deploy.js";
32

43
/**
5-
* Deploys a contract named "YourContract" using the deployer account and
6-
* constructor arguments set to the deployer address
4+
* Deploys a contract named "Voting" using the deployer account.
75
*
8-
* @param hre HardhatRuntimeEnvironment object.
6+
* On localhost, the deployer account is the one that comes with Hardhat, which is already funded.
7+
*
8+
* When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account
9+
* should have sufficient balance to pay for the gas fees for contract creation.
10+
*
11+
* You can generate a random account with `yarn generate` or `yarn account:import` to import your
12+
* existing PK which will fill DEPLOYER_PRIVATE_KEY_ENCRYPTED in the .env file (used in hardhat.config.ts).
13+
* Run `yarn account` to check the deployer balance on every network.
914
*/
10-
const deployYourVotingContract: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
11-
/*
12-
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.
13-
14-
When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account
15-
should have sufficient balance to pay for the gas fees for contract creation.
16-
17-
You can generate a random account with `yarn generate` or `yarn account:import` to import your
18-
existing PK which will fill DEPLOYER_PRIVATE_KEY_ENCRYPTED in the .env file (then used on hardhat.config.ts)
19-
You can run the `yarn account` command to check your balance in every network.
20-
*/
21-
const { deployer } = await hre.getNamedAccounts();
22-
const { deploy } = hre.deployments;
15+
export default deployScript(
16+
async ({ deploy, namedAccounts }) => {
17+
const { deployer } = namedAccounts;
2318

24-
const ownerAddress = "0x0000000000000000000000000000000000000001";
19+
const ownerAddress = "0x0000000000000000000000000000000000000001";
2520

26-
/// checkpoint 6 //////
27-
const verifierAddress = "0x0000000000000000000000000000000000000002"; // placeholder
28-
// const verifier = await deploy("HonkVerifier", {
29-
// from: deployer,
30-
// log: true,
31-
// autoMine: true,
32-
// });
33-
34-
/// checkpoint 2 //////
35-
const leanIMTAddress = "0x0000000000000000000000000000000000000003"; // placeholder
36-
// const poseidon3 = await deploy("PoseidonT3", {
37-
// from: deployer,
38-
// log: true,
39-
// autoMine: true,
40-
// });
41-
42-
// const leanIMT = await deploy("LeanIMT", {
43-
// from: deployer,
44-
// log: true,
45-
// autoMine: true,
46-
// libraries: {
47-
// PoseidonT3: poseidon3.address,
48-
// },
49-
// });
50-
51-
await deploy("Voting", {
52-
from: deployer,
53-
// Contract constructor arguments
5421
/// checkpoint 6 //////
55-
args: [ownerAddress, verifierAddress, "Should we build zk apps?"],
56-
log: true,
57-
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
58-
// automatically mining the contract deployment transaction. There is no effect on live networks.
59-
autoMine: true,
60-
libraries: {
61-
/// checkpoint 2 //////
62-
LeanIMT: leanIMTAddress,
63-
},
64-
});
65-
};
22+
const verifierAddress = "0x0000000000000000000000000000000000000002"; // placeholder
23+
// const verifier = await deploy("HonkVerifier", {
24+
// account: deployer,
25+
// artifact: artifacts.HonkVerifier,
26+
// args: [],
27+
// });
28+
29+
/// checkpoint 2 //////
30+
const leanIMTAddress = "0x0000000000000000000000000000000000000003"; // placeholder
31+
// const poseidon3 = await deploy("PoseidonT3", {
32+
// account: deployer,
33+
// artifact: artifacts.PoseidonT3,
34+
// args: [],
35+
// });
6636

67-
export default deployYourVotingContract;
37+
// const leanIMT = await deploy(
38+
// "LeanIMT",
39+
// {
40+
// account: deployer,
41+
// artifact: artifacts.LeanIMT,
42+
// args: [],
43+
// },
44+
// {
45+
// libraries: {
46+
// PoseidonT3: poseidon3.address,
47+
// },
48+
// },
49+
// );
6850

69-
// Tags are useful if you have multiple deploy files and only want to run one of them.
70-
// e.g. yarn deploy --tags YourContract
71-
deployYourVotingContract.tags = ["YourVotingContract"];
51+
await deploy(
52+
"Voting",
53+
{
54+
account: deployer,
55+
artifact: artifacts.Voting,
56+
args: [ownerAddress, verifierAddress, "Should we build zk apps?"],
57+
},
58+
{
59+
libraries: {
60+
LeanIMT: leanIMTAddress,
61+
},
62+
},
63+
);
64+
},
65+
// Tags are useful if you have multiple deploy files and only want to run one of them.
66+
// e.g. yarn deploy --tags YourVotingContract
67+
{ tags: ["YourVotingContract"] },
68+
);

extension/packages/hardhat/hardhat.config.ts.args.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const configOverrides = {
1212
},
1313
},
1414
],
15+
npmFilesToBuild: ["poseidon-solidity/PoseidonT3.sol", "@zk-kit/lean-imt.sol/LeanIMT.sol"],
1516
},
1617
networks: {
1718
hardhat: {

extension/packages/hardhat/test/Voting.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { expect } from "chai";
2-
import { ethers } from "hardhat";
3-
import type { Voting } from "../typechain-types";
4-
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
2+
import { network } from "hardhat";
3+
import type { Voting } from "../types/ethers-contracts/index.js";
4+
import { anyValue } from "@nomicfoundation/hardhat-ethers-chai-matchers/withArgs";
55

66
describe("🗳️ ZK Voting Challenge", function () {
7+
let ethers: Awaited<ReturnType<typeof network.create>>["ethers"];
8+
9+
before(async function () {
10+
({ ethers } = await network.create());
11+
});
12+
713
let contractArtifact = "";
814
if (process.env.CONTRACT_ADDRESS) {
915
contractArtifact = `contracts/download-${process.env.CONTRACT_ADDRESS}.sol:Voting`;
@@ -25,10 +31,14 @@ describe("🗳️ ZK Voting Challenge", function () {
2531
await leanIMT.waitForDeployment();
2632

2733
const VotingFactory = await ethers.getContractFactory(contractArtifact, {
28-
libraries: { "@zk-kit/lean-imt.sol/LeanIMT.sol:LeanIMT": await leanIMT.getAddress() },
34+
libraries: { LeanIMT: await leanIMT.getAddress() },
2935
});
3036
const verifierZero = "0x0000000000000000000000000000000000000000";
31-
const voting = (await VotingFactory.deploy(owner.address, verifierZero, "Should we build zk apps?")) as Voting;
37+
const voting = (await VotingFactory.deploy(
38+
owner.address,
39+
verifierZero,
40+
"Should we build zk apps?",
41+
)) as unknown as Voting;
3242
await voting.waitForDeployment();
3343

3444
return { voting, owner, alice, bob };
@@ -52,7 +62,7 @@ describe("🗳️ ZK Voting Challenge", function () {
5262
await voting.connect(owner).addVoters([alice.address, bob.address], [true, true]);
5363

5464
const duplicateCommitment = 222n;
55-
await expect(voting.connect(alice).register(duplicateCommitment)).to.not.be.reverted;
65+
await expect(voting.connect(alice).register(duplicateCommitment)).to.not.be.revert(ethers);
5666
await expect(voting.connect(bob).register(duplicateCommitment))
5767
.to.be.revertedWithCustomError(voting, "Voting__CommitmentAlreadyAdded")
5868
.withArgs(duplicateCommitment);
@@ -63,7 +73,7 @@ describe("🗳️ ZK Voting Challenge", function () {
6373

6474
await voting.connect(owner).addVoters([alice.address], [true]);
6575

66-
await expect(voting.connect(alice).register(333n)).to.not.be.reverted;
76+
await expect(voting.connect(alice).register(333n)).to.not.be.revert(ethers);
6777
await expect(voting.connect(alice).register(444n)).to.be.revertedWithCustomError(
6878
voting,
6979
"Voting__NotAllowedToVote",
@@ -115,9 +125,13 @@ describe("🗳️ ZK Voting Challenge", function () {
115125
await verifier.waitForDeployment();
116126

117127
const VotingFactory = await ethers.getContractFactory(contractArtifact, {
118-
libraries: { "@zk-kit/lean-imt.sol/LeanIMT.sol:LeanIMT": await leanIMT.getAddress() },
128+
libraries: { LeanIMT: await leanIMT.getAddress() },
119129
});
120-
const voting = (await VotingFactory.deploy(owner.address, await verifier.getAddress(), "Question?")) as Voting;
130+
const voting = (await VotingFactory.deploy(
131+
owner.address,
132+
await verifier.getAddress(),
133+
"Question?",
134+
)) as unknown as Voting;
121135
await voting.waitForDeployment();
122136

123137
// allowlist and register a voter to set a non-zero root

extension/packages/nextjs/app/voting/_challengeComponents/CreateCommitment.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { useState } from "react";
44
////// Checkpoint 7 //////
55
// import { Fr } from "@aztec/bb.js";
6-
// import { toHex } from "viem";
76
// import { poseidon2 } from "poseidon-lite";
7+
// import { toHex } from "viem";
88
import { useAccount } from "wagmi";
99
import { useDeployedContractInfo, useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth";
1010
import { useChallengeState } from "~~/services/store/challengeStore";

extension/packages/nextjs/app/voting/_challengeComponents/GenerateProof.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { useState } from "react";
66
// // @ts-ignore
77
// import { Noir } from "@noir-lang/noir_js";
88
// import { LeanIMT } from "@zk-kit/lean-imt";
9-
// import { encodeAbiParameters, toHex } from "viem";
109
// import { poseidon1, poseidon2 } from "poseidon-lite";
1110
import { useAccount } from "wagmi";
1211
import { useDeployedContractInfo, useScaffoldReadContract } from "~~/hooks/scaffold-eth";

0 commit comments

Comments
 (0)