Skip to content
Draft
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
141 changes: 138 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Before you begin, you need to install the following tools:
- [Node (>= v20.18.3)](https://nodejs.org/en/download/)
- [Yarn (v2+)](https://yarnpkg.com/getting-started/install)
- [Git](https://git-scm.com/downloads)
- [Foundry](https://book.getfoundry.sh/getting-started/installation) (If you chose Foundry as solidity framework)
- [Nargo](https://noir-lang.org/docs/getting_started/quick_start#installation) (v1.0.0-beta.3)
- [bb](https://barretenberg.aztec.network/docs/getting_started/) (v0.82.2)

Expand Down Expand Up @@ -92,6 +93,8 @@ npx create-eth@2.0.13 -e scaffold-eth/se-2-challenges:challenge-zk-voting challe
cd challenge-zk-voting
```

> When prompted, choose your preferred solidity framework (Hardhat or Foundry)

In the same terminal, start your local network (a blockchain emulator in your computer):

```sh
Expand Down Expand Up @@ -163,8 +166,23 @@ Our contract will support three main functions:

🔍 Next, switch to the **`Debug Contracts`** page. For now, you should see just one contract there — **`Voting`**.

<Tabs>
<Tab label="Hardhat">

**Hardhat**

📁 The contract lives in **`packages/hardhat/contracts/Voting.sol`**

</Tab>
<Tab label="Foundry">

**Foundry**

📁 The contract lives in **`packages/foundry/contracts/Voting.sol`**

</Tab>
</Tabs>

🔍 Open it up and check out the placeholder functions. Each of them represents a key piece of the voting logic.
If you can already explain what they’re supposed to do, you’re ahead of the game! 😎

Expand Down Expand Up @@ -364,23 +382,58 @@ Scroll down to the functions **`getVotingData()`** and **`getVoterData(address _

Then run:

<Tabs>
<Tab label="Hardhat">

**Hardhat**

```sh
yarn test --grep "Checkpoint2"
```

</Tab>
<Tab label="Foundry">

**Foundry**

```sh
yarn test --match-test "Checkpoint2"
```

</Tab>
</Tabs>

### 🚀 Tests Passed? You’re Almost There!

Great job! If your tests are passing, you’re just one step away from deployment! 🚀

Before deploying, make one important change:

<Tabs>
<Tab label="Hardhat">

**Hardhat**

1. Open **`00_deploy_your_voting_contract.ts`**
2. Set your address as the `ownerAddress`
3. Uncomment deployment of both `poseidon3` and `leanIMT`
4. Set LeanIMT library address (`leanIMT.address`) at line 62

> 💡 **Poseidon3** is the hash function we use. More on that later.

</Tab>
<Tab label="Foundry">

**Foundry**

1. Open **`DeployVoting.s.sol`**
2. Set your address as the `ownerAddress`

> 💡 In Foundry, library linking is handled automatically at compile time — no need to deploy PoseidonT3 or LeanIMT separately.

</Tab>
</Tabs>

Once that’s done, you’re ready to deploy! 🔗

Run `yarn deploy` and check out the front-end
Expand Down Expand Up @@ -952,12 +1005,31 @@ You’ve built the circuit, created the verifier contract — now it’s time to

### 🔹 Step 1: Bring in the Verifier Contract

<Tabs>
<Tab label="Hardhat">

**Hardhat**

1. Replace the placeholder verifier contract **`Verifier.sol`** in **`packages/hardhat/contracts`** with the newly generated contract located in **`packages/circuits/target`**.
2. Open **`00_deploy_your_voting_contract.ts`** and:
- Uncomment the verifier deployment
- Comment out the `verifierAddress`
- Update the `args` to match your setup

</Tab>
<Tab label="Foundry">

**Foundry**

1. Replace the placeholder verifier contract **`Verifier.sol`** in **`packages/foundry/contracts`** with the newly generated contract located in **`packages/circuits/target`**.
2. Open **`DeployVoting.s.sol`** and:
- Uncomment the verifier deployment
- Comment out the placeholder `verifierAddress`
- Update the constructor call to match your setup

</Tab>
</Tabs>

3. In **`Voting.sol`**:
- At the top, import the verifier contract (just uncomment the existing line)
- In the constructor, initialize the verifier and store it in a variable called `i_verifier`
Expand Down Expand Up @@ -1116,10 +1188,27 @@ function vote(bytes memory _proof, bytes32 _nullifierHash, bytes32 _root, bytes3

Once implemented, run your tests to make sure everything works:

<Tabs>
<Tab label="Hardhat">

**Hardhat**

```sh
yarn test --grep "Checkpoint6"
```

</Tab>
<Tab label="Foundry">

**Foundry**

```sh
yarn test --match-test "Checkpoint6"
```

</Tab>
</Tabs>

### **✅ Tests Passed? You're So Close!**

If your tests are green, congratulations — you’ve just completed the **core `Voting.sol` contract!** 🎉
Expand Down Expand Up @@ -1813,10 +1902,27 @@ For **production-grade apps**, you should generate your own API keys to avoid hi

Configure your keys here:

<Tabs>
<Tab label="Hardhat">

**Hardhat**

- 🔷 **`ALCHEMY_API_KEY`** in `packages/hardhat/.env` and `packages/nextjs/.env.local` → [Get key from Alchemy](https://dashboard.alchemy.com/)
- 🔑 **`NEXT_PUBLIC_PIMLICO_API_KEY`** in `packages/nextjs/.env.local` → [Get key from Pimlico](https://dashboard.pimlico.io/)
- 📃 **`ETHERSCAN_API_KEY`** in `packages/hardhat/.env` → [Get key from Etherscan](https://etherscan.io/myapikey)

</Tab>
<Tab label="Foundry">

**Foundry**

- 🔷 **`ALCHEMY_API_KEY`** in `packages/foundry/.env` and `packages/nextjs/.env.local` → [Get key from Alchemy](https://dashboard.alchemy.com/)
- 🔑 **`NEXT_PUBLIC_PIMLICO_API_KEY`** in `packages/nextjs/.env.local` → [Get key from Pimlico](https://dashboard.pimlico.io/)
- 📃 **`ETHERSCAN_API_KEY`** in `packages/foundry/.env` → [Get key from Etherscan](https://etherscan.io/myapikey)

</Tab>
</Tabs>

> 💬 Hint: Store environment variables for **Next.js** in Vercel/system env config for live apps, and use `.env.local` for local testing.

### Deploying Your Smart Contracts
Expand All @@ -1827,11 +1933,28 @@ Configure your keys here:

⛽️ You will need to send ETH to your deployer address with your wallet, or obtain it from a public faucet of your chosen network.

> 🚨 Don’t forget to set the owner address inside the 00_deploy_your_voting_contract.ts .
<Tabs>
<Tab label="Hardhat">

**Hardhat**

> 🚨 Don't forget to set the owner address inside the `00_deploy_your_voting_contract.ts`.

🚀 Run `yarn deploy --network sepolia` to deploy your smart contract to Sepolia.

> 💬 Hint: You can set the defaultNetwork in hardhat.config.ts to sepolia OR you can yarn deploy --network sepolia.

🚀 Run `yarn deploy --network sepolia` to deploy your smart contract to Sepolia.
</Tab>
<Tab label="Foundry">

> 💬 Hint: You can set the defaultNetwork in hardhat.config.ts to sepolia OR you can yarn deploy --network sepolia.
**Foundry**

> 🚨 Don't forget to set the owner address inside the `DeployVoting.s.sol`.

🚀 Run `yarn deploy --network sepolia` to deploy your smart contract to Sepolia.

</Tab>
</Tabs>

💻 Inside `scaffold.config.ts` change the `targetNetwork` to `chains.sepolia`. View your front-end at http://localhost:3000 and verify you see the correct network Sepolia.

Expand Down Expand Up @@ -1953,3 +2076,15 @@ But this is just the beginning. The same **commitment + nullifier** pattern that
This challenge is your **entry point into a new design space.** 💥

**What will you build with Noir and ZK circuits? 🧪✨**

## AI-Guided Learning Mode (Optional)

This challenge supports an interactive AI learning mode. Instead of reading instructions above, you can let an AI guide you step by step.

**How to use:**
1. Open a terminal in the project root
2. Run `/start` to begin the guided challenge
3. The AI will teach concepts and give you coding tasks
4. Say `check` to validate your code, `hint` for help, or `/skip` to skip a task

> Note: If you chose Foundry as your framework, the screenshots in this README show the Hardhat version, but the contract logic and challenge flow are identical.
20 changes: 15 additions & 5 deletions extension/.ai/CHALLENGE.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ difficulty: "advanced"
estimated_time: "6 - 16 hours"

setup:
file: "packages/hardhat/contracts/Voting.sol"
file:
hardhat: "packages/hardhat/contracts/Voting.sol"
foundry: "packages/foundry/contracts/Voting.sol"

welcome_message: |
Welcome to the ZK Voting Challenge!
Expand Down Expand Up @@ -169,8 +171,12 @@ checkpoints:
4. Check `getVotingData()` — you should see Merkle tree data (size, depth, root).

Say **"check"** when you're ready!
file: "packages/hardhat/contracts/Voting.sol"
test: "yarn test --grep 'Checkpoint2'"
file:
hardhat: "packages/hardhat/contracts/Voting.sol"
foundry: "packages/foundry/contracts/Voting.sol"
test:
hardhat: "yarn test --grep 'Checkpoint2'"
foundry: "yarn test --match-test 'Checkpoint2'"
hints:
- "The two guard checks use existing state: `s_voters` (allowlist) and the new `s_hasRegistered` mapping."
- |
Expand Down Expand Up @@ -719,8 +725,12 @@ checkpoints:
4. Head to the **Voting** page — the full voting flow is now functional on the contract side!

Say **"check"** when you're ready!
file: "packages/hardhat/contracts/Voting.sol"
test: "yarn test --grep 'Checkpoint6'"
file:
hardhat: "packages/hardhat/contracts/Voting.sol"
foundry: "packages/foundry/contracts/Voting.sol"
test:
hardhat: "yarn test --grep 'Checkpoint6'"
foundry: "yarn test --match-test 'Checkpoint6'"
hints:
- "Don't forget the setup steps: replace Verifier.sol, update the deploy script, uncomment the import, add the two state variables, and initialize `i_verifier` in the constructor."
- |
Expand Down
7 changes: 5 additions & 2 deletions extension/.ai/instructions/skip-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Read `.ai/CHALLENGE.yaml` and find the current checkpoint by its ID.

- If the current checkpoint does NOT have a `task` field, tell the user:
"This checkpoint doesn't have a coding task to skip. Say 'hint' if you need help with the current question."
- If it has a `task` field, continue to Step 3
- If it has a `task` field, continue to Step 2b

### Step 2b: Resolve Framework-Specific Fields
CHALLENGE.yaml `file:` and `test:` fields contain framework-specific values (e.g. `hardhat:` and `foundry:`). Detect which framework this project uses by checking which directory exists (`packages/hardhat/` vs `packages/foundry/`). Use the matching key for all `file:` and `test:` lookups throughout the skip flow.

### Step 3: Show the Solution
Display the solution from `task.solution` with an explanation:
Expand All @@ -38,7 +41,7 @@ Read the current contract file (`task.file`) and apply the solution code:
- Be careful to place code in the correct sections of the contract

### Step 5: Run Tests
Execute the `task.test` command (e.g., `yarn test --grep "Checkpoint1"`) to verify the solution works.
Execute the `task.test` command (resolved for the detected framework, e.g., `yarn test --grep "Checkpoint1"` for Hardhat or `yarn test --match-test "Checkpoint1"` for Foundry) to verify the solution works.
- If tests pass: continue to Step 6
- If tests fail: debug and fix (this shouldn't happen with correct solutions)

Expand Down
5 changes: 4 additions & 1 deletion extension/.ai/instructions/start-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Read the file `.ai/CHALLENGE.yaml` to understand:
- All checkpoints with their context, questions, tasks, and code unlocks
- Whether each checkpoint is a **concept checkpoint** (has `unlocks`) or a **code-writing checkpoint** (has `task`)

### Step 1b: Resolve Framework-Specific Fields
CHALLENGE.yaml `file:` and `test:` fields contain framework-specific values (e.g. `hardhat:` and `foundry:`). Detect which framework this project uses by checking which directory exists (`packages/hardhat/` vs `packages/foundry/`). Use the matching key for all `file:` and `test:` lookups throughout the challenge.

### Step 2: Apply Setup (if applicable)
Check if CHALLENGE.yaml has a `setup.template` field:

Expand Down Expand Up @@ -270,7 +273,7 @@ The user will respond with one of:

### Phase 5: Validate with Tests

Run the test command from `task.test` (e.g., `yarn test --grep "Checkpoint1"`).
Run the test command from `task.test` (resolved for the detected framework, e.g., `yarn test --grep "Checkpoint1"` for Hardhat or `yarn test --match-test "Checkpoint1"` for Foundry).

**If ALL tests pass:**
```
Expand Down
Loading