Skip to content

Commit 4cc6980

Browse files
jimmychu0807weipooppys93030timou0911csiejimmyliu
authored
Add CLI Foundry Template (cont.) (#905)
* Semaphore identity example code bug fix * Receive suggestion for consistency * chore: forge init * forge install: forge-std v1.9.2 * Foundry CLI First Draft * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * forge install: forge-std v1.9.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * forge install: forge-std v1.9.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * forge install: forge-std v1.9.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * forge install: forge-std v1.9.2 * modules * forge install: semaphore v4.0.3 * forge install: zk-kit.solidity * forge install: poseidon-solidity v0.0.5 * forge install: openzeppelin-contracts v5.0.2 * forge install: forge-std v1.9.2 * change test name * modify declaration of semaphore and verifier * Modify Test Function Name * Add Test Chain Target * forge std install * refactor(cli-template-contracts-foundry): change default Anvil address and private key * chore(cli-template-contracts-foundry): add comments * refactor(cli-template-contracts-foundry): add Semaphore & SemaphoreVerifier addresses for test chain * chore(cli-template-contracts-foundry): add forge coverage for Makefile * chore(cli-template-contracts-foundry): add env.example * docs(cli-template-contracts-foundry): add command instructions * updated * forge build works * Fixed for linting * chore(cli-template-contracts-foundry): make the lint, prettier, and lint-staged pass * chore(cli-template-contracts-foundry): replace Makefile(removed) with package.json * chore(cli-template-contracts-foundry): passing the ci test * updated test * feat(cli-template-contracts-foundry): complete cli-template-contracts-foundry re #854, #185 * Update dependencies * Add explanation on `yarn dev` * fix(cli-template-contracts-foundry): fix `yarn dev` command and add docs on integrate w/ boilerplate * Added yarnrc * updated version * Added Foundry in template option --------- Co-authored-by: weipooppys93030 <[email protected]> Co-authored-by: timou0911 <[email protected]> Co-authored-by: csiejimmyliu <[email protected]>
1 parent 6b04ec0 commit 4cc6980

File tree

15 files changed

+1347
-1
lines changed

15 files changed

+1347
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SEPOLIA_RPC_URL=
2+
PRIVATE_KEY=
3+
ETHERSCAN_API_KEY=
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
node_modules
2+
.env
3+
4+
# solidity-coverage files
5+
/coverage
6+
/coverage.json
7+
8+
# Output of 'npm pack'
9+
*.tgz
10+
11+
# Logs
12+
logs
13+
*.log
14+
npm-debug.log*
15+
yarn-debug.log*
16+
yarn-error.log*
17+
lerna-debug.log*
18+
.pnpm-debug.log*
19+
20+
# Optional npm cache directory
21+
.npm
22+
.DS_Store
23+
24+
# yarn v3
25+
.pnp.*
26+
.pnp.js
27+
.yarn/*
28+
!.yarn/patches
29+
!.yarn/plugins
30+
!.yarn/releases
31+
!.yarn/sdks
32+
!.yarn/versions
33+
34+
# Diagnostic reports (https://nodejs.org/api/report.html)
35+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
36+
37+
# Foundry artifact
38+
cache/
39+
out/
40+
41+
# artifact for deploying on local Anvil node
42+
**/31337
43+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"semi": false,
3+
"arrowParens": "always",
4+
"trailingComma": "none",
5+
"plugins": ["prettier-plugin-solidity"]
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "solhint:recommended",
3+
"rules": {
4+
"func-visibility": ["error", { "ignoreConstructors": true }]
5+
}
6+
}

packages/cli-template-contracts-foundry/.yarn/releases/yarn-4.1.0.cjs

+893
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
compressionLevel: mixed
2+
3+
enableGlobalCache: false
4+
5+
nodeLinker: node-modules
6+
7+
yarnPath: .yarn/releases/yarn-4.1.0.cjs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Semaphore Foundry Template
2+
3+
This project demonstrates a basic Semaphore use case. It comes with a sample contract, a test for that contract and a sample script that deploys that contract.
4+
5+
## Prerequisites
6+
7+
This project requires [**Foundry**](https://getfoundry.sh/), and thus a [**Rust environment**](https://www.rust-lang.org/), installed in the machine.
8+
9+
## Install
10+
11+
### Install dependencies
12+
13+
```bash
14+
yarn
15+
```
16+
17+
## Usage
18+
19+
### Compile contracts
20+
21+
```bash
22+
yarn compile
23+
```
24+
25+
### Test contracts
26+
27+
```bash
28+
yarn test
29+
```
30+
31+
You can also generate a test coverage report:
32+
33+
```bash
34+
yarn test:coverage
35+
```
36+
37+
Or a test gas report:
38+
39+
```bash
40+
yarn test:gas-report
41+
```
42+
43+
You can also start a local [Anvil node](https://book.getfoundry.sh/anvil/) with Semaphore and Feedback contracts deployed on it with:
44+
45+
```bash
46+
yarn dev
47+
```
48+
49+
### Code quality and formatting
50+
51+
Run [solhint](https://github.com/protofire/solhint) to analyze the code and catch bugs:
52+
53+
```bash
54+
yarn lint
55+
```
56+
57+
Run [Prettier](https://prettier.io/) to check formatting rules:
58+
59+
```bash
60+
yarn prettier
61+
```
62+
63+
Or to automatically format the code:
64+
65+
```bash
66+
yarn prettier:write
67+
```
68+
69+
### Integrating with Semaphore Boilerplate
70+
71+
You can also integrate this project with [Semaphore Boilerplate](https://github.com/semaphore-protocol/boilerplate), using this project as the contract end and connecting with Boilerplate front end.
72+
73+
1. In `cli-template-contracts-foundry` package directory, run:
74+
75+
```sh
76+
yarn install
77+
yarn dev
78+
```
79+
80+
After running `yarn dev`, notice the output of
81+
82+
```sh
83+
# ...
84+
# ...
85+
86+
== Return ==
87+
feedbackAddr: address 0x6f1AFCA8BCA87bF02091AF6187a5002802f9FB31
88+
semaphoreAddr: address 0xb730ce6CAE3FB706e83E4E00dFA31623966570eB
89+
semaphoreVerifierAddr: address 0xE2c114f548bEf410eaCe04D0390b61cc963df295
90+
91+
# ...
92+
# ...
93+
```
94+
95+
2. Now, with another terminal, clone Semaphore Boilerplate down:
96+
97+
```sh
98+
# Clone Semaphore boilerplate and build dependencies
99+
git clone https://github.com/semaphore-protocol/boilerplate.git
100+
cd boilerplate
101+
yarn install
102+
103+
# Use the sample .env.example
104+
cp .env.example .env
105+
```
106+
107+
3. Open the file `apps/web-app/.env.development`. Modify the values of `NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS` and `NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS` with **feedbackAddr** and **semaphoreAddr** values shown in step 1.
108+
109+
4. Run the Boilerplate front end:
110+
111+
```sh
112+
yarn dev:web-app
113+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[profile.default]
2+
src = "src"
3+
out = "out"
4+
script = "script"
5+
libs = ["node_modules"]
6+
allow_paths = ["*", "../.."]
7+
8+
[rpc_endpoints]
9+
anvil = "http://127.0.0.1:8545"
10+
# sepolia = "${SEPOLIA_RPC_URL}"
11+
12+
[etherscan]
13+
# sepolia = { key = "${ETHERSCAN_API_KEY}" }
14+
15+
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@semaphore-protocol/cli-template-contracts-foundry",
3+
"version": "4.7.3",
4+
"description": "Semaphore Foundry template.",
5+
"license": "Unlicense",
6+
"devDependencies": {
7+
"@semaphore-protocol/contracts": "4.7.3",
8+
"@zk-kit/lean-imt.sol": "2.0.0",
9+
"forge-std": "github:foundry-rs/forge-std#v1.9.4",
10+
"poseidon-solidity": "0.0.5",
11+
"prettier": "^3.2.5",
12+
"prettier-plugin-solidity": "^1.3.1",
13+
"solhint": "^4.1.1",
14+
"wait-on": "^8.0.1"
15+
},
16+
"scripts": {
17+
"dev": "anvil & (wait-on tcp:8545 && forge script script/DeployFeedback.s.sol --rpc-url anvil --broadcast --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)",
18+
"compile": "forge build",
19+
"clean": "forge clean",
20+
"test": "forge test -vvv",
21+
"test:report-gas": "forge test --gas-report",
22+
"test:coverage": "forge coverage",
23+
"lint": "yarn solhint \"{script,src,test}/**/*.sol\"",
24+
"prettier": "prettier -c \"**/*.{json,md,svg,yml,sol}\"",
25+
"prettier:write": "prettier -w \"**/*.{json,md,svg,yml,sol}\"",
26+
"check": "yarn test & yarn lint & yarn prettier"
27+
},
28+
"files": [
29+
"src",
30+
"test",
31+
"script",
32+
"package.json",
33+
"foundry.toml",
34+
"remappings.txt",
35+
"README.md"
36+
],
37+
"publishConfig": {
38+
"access": "public"
39+
},
40+
"packageManager": "[email protected]"
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@semaphore/contracts/=./node_modules/@semaphore-protocol/contracts/
2+
@zk-kit/lean-imt.sol/=./node_modules/@zk-kit/lean-imt.sol/
3+
forge-std/=./node_modules/forge-std/src/
4+
poseidon-solidity/=./node_modules/poseidon-solidity/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
import {Feedback} from "../src/Feedback.sol";
5+
import {Semaphore} from "@semaphore/contracts/Semaphore.sol";
6+
import {SemaphoreVerifier} from "@semaphore/contracts/base/SemaphoreVerifier.sol";
7+
import {ISemaphoreVerifier} from "@semaphore/contracts/interfaces/ISemaphoreVerifier.sol";
8+
import {Script} from "forge-std/Script.sol";
9+
10+
// Passing SALT parameter to use CREATE2 for deterministic contract address
11+
bytes32 constant SALT = bytes32(0);
12+
13+
contract DeployFeedback is Script {
14+
function run() external returns (address feedbackAddr, address semaphoreAddr, address semaphoreVerifierAddr) {
15+
// Default to use the first test user private key of anvil node
16+
uint256 deployerPrivateKey = vm.envOr(
17+
"PRIVATE_KEY",
18+
uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)
19+
);
20+
21+
vm.startBroadcast(deployerPrivateKey);
22+
23+
// Deploy SemaphoreVerifier
24+
SemaphoreVerifier semaphoreVerifierContract = new SemaphoreVerifier{salt: SALT}();
25+
semaphoreVerifierAddr = address(semaphoreVerifierContract);
26+
27+
// Deploy Semaphore
28+
Semaphore semaphoreContract = new Semaphore{salt: SALT}(ISemaphoreVerifier(semaphoreVerifierAddr));
29+
semaphoreAddr = address(semaphoreContract);
30+
31+
// Deploy Feedback
32+
Feedback feedbackContract = new Feedback{salt: SALT}(semaphoreAddr);
33+
feedbackAddr = address(feedbackContract);
34+
35+
vm.stopBroadcast();
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
import {ISemaphore} from "@semaphore/contracts/interfaces/ISemaphore.sol";
5+
6+
contract Feedback {
7+
ISemaphore public semaphore;
8+
9+
uint256 public groupId;
10+
11+
constructor(address semaphoreAddress) {
12+
semaphore = ISemaphore(semaphoreAddress);
13+
14+
groupId = semaphore.createGroup();
15+
}
16+
17+
function joinGroup(uint256 identityCommitment) external {
18+
semaphore.addMember(groupId, identityCommitment);
19+
}
20+
21+
function sendFeedback(
22+
uint256 merkleTreeDepth,
23+
uint256 merkleTreeRoot,
24+
uint256 nullifier,
25+
uint256 feedback,
26+
uint256[8] calldata points
27+
) external {
28+
ISemaphore.SemaphoreProof memory proof = ISemaphore.SemaphoreProof(
29+
merkleTreeDepth,
30+
merkleTreeRoot,
31+
nullifier,
32+
feedback,
33+
groupId,
34+
points
35+
);
36+
37+
semaphore.validateProof(groupId, proof);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
import {Test} from "forge-std/Test.sol";
5+
import {ISemaphore} from "@semaphore/contracts/interfaces/ISemaphore.sol";
6+
import {ISemaphoreGroups} from "@semaphore/contracts/interfaces/ISemaphoreGroups.sol";
7+
import {Feedback} from "../src/Feedback.sol";
8+
import {DeployFeedback} from "../script/DeployFeedback.s.sol";
9+
10+
contract FeedbackTest is Test {
11+
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);
12+
13+
Feedback internal feedbackContract;
14+
ISemaphore internal semaphoreContract;
15+
ISemaphoreGroups internal semaphoreGroups;
16+
uint256 internal groupId;
17+
18+
function setUp() external {
19+
DeployFeedback deployFeedback = new DeployFeedback();
20+
(address feedbackAddress, address semaphoreAddress, ) = deployFeedback.run();
21+
feedbackContract = Feedback(feedbackAddress);
22+
semaphoreContract = ISemaphore(semaphoreAddress);
23+
semaphoreGroups = ISemaphoreGroups(semaphoreAddress);
24+
groupId = feedbackContract.groupId();
25+
}
26+
27+
function testGroupCreatedInConstructor() public view {
28+
uint256 groupCount = semaphoreContract.groupCounter();
29+
assertEq(groupCount, 1);
30+
}
31+
32+
function testJoinGroup() public {
33+
// The commitment below is generated with private key of the first account in Anvil
34+
uint256 identityCommitment = 15072455385723004728391568434269917452175057560864330595979104241296826134229;
35+
36+
// Test: expect an event emitted. Check for all event topics and data
37+
vm.expectEmit(true, true, true, true);
38+
emit MemberAdded(groupId, 0, identityCommitment, identityCommitment);
39+
40+
feedbackContract.joinGroup(identityCommitment);
41+
}
42+
43+
function testSendFeedback() public {
44+
uint256[] memory commitments = new uint256[](2);
45+
commitments[0] = uint256(11005642493773047649202648265396872197147567800455247120861783398111750817516);
46+
commitments[1] = uint256(14473821761500463903284857947161896352613497175238126022206384102438097355186);
47+
48+
for (uint256 i = 0; i < commitments.length; ++i) {
49+
feedbackContract.joinGroup(commitments[i]);
50+
}
51+
52+
uint256 merkleTreeDepth = 1;
53+
uint256 merkleTreeRoot = semaphoreGroups.getMerkleTreeRoot(groupId);
54+
uint256 feedback = uint256(bytes32("Hello World"));
55+
56+
// These values are computed by running through @semaphore-protocol/circuits
57+
uint256 nullifier = 14622092170088252518938850323258916742048811914834592843410744760450844885096;
58+
uint256[8] memory points = [
59+
2004484873491928515306456072357737929124240734208600886081152392890959117520,
60+
21291026142870585364296731900941597996672838511394659364623185352043543529323,
61+
4657264777014371046112557309523098953851041383509685591373847255581509612788,
62+
6904165961903336246592681066375875983213983935764940579845010085396463328555,
63+
1952750241178995674697344628236393389729638396609772141225880353616301956443,
64+
106937615136633409337870509099767689510837462832227699340906789167349502398,
65+
13080722838047436988558418790480431472161933638137155324683844808531903905810,
66+
2547578906197450986657523555784319153413167960139250957065929818900731634820
67+
];
68+
69+
vm.expectEmit(true, true, true, true);
70+
emit ISemaphore.ProofValidated(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, feedback, groupId, points);
71+
72+
feedbackContract.sendFeedback(merkleTreeDepth, merkleTreeRoot, nullifier, feedback, points);
73+
}
74+
}

0 commit comments

Comments
 (0)