Skip to content

Commit

Permalink
Add CLI Foundry Template (cont.) (#905)
Browse files Browse the repository at this point in the history
* 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 <55434365+weipooppys93030@users.noreply.github.com>
Co-authored-by: timou0911 <x0928048316@gmail.com>
Co-authored-by: csiejimmyliu <91661606+csiejimmyliu@users.noreply.github.com>
  • Loading branch information
4 people authored Dec 17, 2024
1 parent 6b04ec0 commit 4cc6980
Show file tree
Hide file tree
Showing 15 changed files with 1,347 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/cli-template-contracts-foundry/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
SEPOLIA_RPC_URL=
PRIVATE_KEY=
ETHERSCAN_API_KEY=
43 changes: 43 additions & 0 deletions packages/cli-template-contracts-foundry/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
node_modules
.env

# solidity-coverage files
/coverage
/coverage.json

# Output of 'npm pack'
*.tgz

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Optional npm cache directory
.npm
.DS_Store

# yarn v3
.pnp.*
.pnp.js
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Foundry artifact
cache/
out/

# artifact for deploying on local Anvil node
**/31337

6 changes: 6 additions & 0 deletions packages/cli-template-contracts-foundry/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": false,
"arrowParens": "always",
"trailingComma": "none",
"plugins": ["prettier-plugin-solidity"]
}
6 changes: 6 additions & 0 deletions packages/cli-template-contracts-foundry/.solhint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "solhint:recommended",
"rules": {
"func-visibility": ["error", { "ignoreConstructors": true }]
}
}
893 changes: 893 additions & 0 deletions packages/cli-template-contracts-foundry/.yarn/releases/yarn-4.1.0.cjs

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions packages/cli-template-contracts-foundry/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
compressionLevel: mixed

enableGlobalCache: false

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.1.0.cjs
113 changes: 113 additions & 0 deletions packages/cli-template-contracts-foundry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Semaphore Foundry Template

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.

## Prerequisites

This project requires [**Foundry**](https://getfoundry.sh/), and thus a [**Rust environment**](https://www.rust-lang.org/), installed in the machine.

## Install

### Install dependencies

```bash
yarn
```

## Usage

### Compile contracts

```bash
yarn compile
```

### Test contracts

```bash
yarn test
```

You can also generate a test coverage report:

```bash
yarn test:coverage
```

Or a test gas report:

```bash
yarn test:gas-report
```

You can also start a local [Anvil node](https://book.getfoundry.sh/anvil/) with Semaphore and Feedback contracts deployed on it with:

```bash
yarn dev
```

### Code quality and formatting

Run [solhint](https://github.com/protofire/solhint) to analyze the code and catch bugs:

```bash
yarn lint
```

Run [Prettier](https://prettier.io/) to check formatting rules:

```bash
yarn prettier
```

Or to automatically format the code:

```bash
yarn prettier:write
```

### Integrating with Semaphore Boilerplate

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.

1. In `cli-template-contracts-foundry` package directory, run:

```sh
yarn install
yarn dev
```

After running `yarn dev`, notice the output of

```sh
# ...
# ...
== Return ==
feedbackAddr: address 0x6f1AFCA8BCA87bF02091AF6187a5002802f9FB31
semaphoreAddr: address 0xb730ce6CAE3FB706e83E4E00dFA31623966570eB
semaphoreVerifierAddr: address 0xE2c114f548bEf410eaCe04D0390b61cc963df295
# ...
# ...
```

2. Now, with another terminal, clone Semaphore Boilerplate down:

```sh
# Clone Semaphore boilerplate and build dependencies
git clone https://github.com/semaphore-protocol/boilerplate.git
cd boilerplate
yarn install
# Use the sample .env.example
cp .env.example .env
```

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.

4. Run the Boilerplate front end:

```sh
yarn dev:web-app
```
15 changes: 15 additions & 0 deletions packages/cli-template-contracts-foundry/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[profile.default]
src = "src"
out = "out"
script = "script"
libs = ["node_modules"]
allow_paths = ["*", "../.."]

[rpc_endpoints]
anvil = "http://127.0.0.1:8545"
# sepolia = "${SEPOLIA_RPC_URL}"

[etherscan]
# sepolia = { key = "${ETHERSCAN_API_KEY}" }

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
41 changes: 41 additions & 0 deletions packages/cli-template-contracts-foundry/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@semaphore-protocol/cli-template-contracts-foundry",
"version": "4.7.3",
"description": "Semaphore Foundry template.",
"license": "Unlicense",
"devDependencies": {
"@semaphore-protocol/contracts": "4.7.3",
"@zk-kit/lean-imt.sol": "2.0.0",
"forge-std": "github:foundry-rs/forge-std#v1.9.4",
"poseidon-solidity": "0.0.5",
"prettier": "^3.2.5",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^4.1.1",
"wait-on": "^8.0.1"
},
"scripts": {
"dev": "anvil & (wait-on tcp:8545 && forge script script/DeployFeedback.s.sol --rpc-url anvil --broadcast --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)",
"compile": "forge build",
"clean": "forge clean",
"test": "forge test -vvv",
"test:report-gas": "forge test --gas-report",
"test:coverage": "forge coverage",
"lint": "yarn solhint \"{script,src,test}/**/*.sol\"",
"prettier": "prettier -c \"**/*.{json,md,svg,yml,sol}\"",
"prettier:write": "prettier -w \"**/*.{json,md,svg,yml,sol}\"",
"check": "yarn test & yarn lint & yarn prettier"
},
"files": [
"src",
"test",
"script",
"package.json",
"foundry.toml",
"remappings.txt",
"README.md"
],
"publishConfig": {
"access": "public"
},
"packageManager": "yarn@4.1.0"
}
4 changes: 4 additions & 0 deletions packages/cli-template-contracts-foundry/remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@semaphore/contracts/=./node_modules/@semaphore-protocol/contracts/
@zk-kit/lean-imt.sol/=./node_modules/@zk-kit/lean-imt.sol/
forge-std/=./node_modules/forge-std/src/
poseidon-solidity/=./node_modules/poseidon-solidity/
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {Feedback} from "../src/Feedback.sol";
import {Semaphore} from "@semaphore/contracts/Semaphore.sol";
import {SemaphoreVerifier} from "@semaphore/contracts/base/SemaphoreVerifier.sol";
import {ISemaphoreVerifier} from "@semaphore/contracts/interfaces/ISemaphoreVerifier.sol";
import {Script} from "forge-std/Script.sol";

// Passing SALT parameter to use CREATE2 for deterministic contract address
bytes32 constant SALT = bytes32(0);

contract DeployFeedback is Script {
function run() external returns (address feedbackAddr, address semaphoreAddr, address semaphoreVerifierAddr) {
// Default to use the first test user private key of anvil node
uint256 deployerPrivateKey = vm.envOr(
"PRIVATE_KEY",
uint256(0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80)
);

vm.startBroadcast(deployerPrivateKey);

// Deploy SemaphoreVerifier
SemaphoreVerifier semaphoreVerifierContract = new SemaphoreVerifier{salt: SALT}();
semaphoreVerifierAddr = address(semaphoreVerifierContract);

// Deploy Semaphore
Semaphore semaphoreContract = new Semaphore{salt: SALT}(ISemaphoreVerifier(semaphoreVerifierAddr));
semaphoreAddr = address(semaphoreContract);

// Deploy Feedback
Feedback feedbackContract = new Feedback{salt: SALT}(semaphoreAddr);
feedbackAddr = address(feedbackContract);

vm.stopBroadcast();
}
}
39 changes: 39 additions & 0 deletions packages/cli-template-contracts-foundry/src/Feedback.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {ISemaphore} from "@semaphore/contracts/interfaces/ISemaphore.sol";

contract Feedback {
ISemaphore public semaphore;

uint256 public groupId;

constructor(address semaphoreAddress) {
semaphore = ISemaphore(semaphoreAddress);

groupId = semaphore.createGroup();
}

function joinGroup(uint256 identityCommitment) external {
semaphore.addMember(groupId, identityCommitment);
}

function sendFeedback(
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256 nullifier,
uint256 feedback,
uint256[8] calldata points
) external {
ISemaphore.SemaphoreProof memory proof = ISemaphore.SemaphoreProof(
merkleTreeDepth,
merkleTreeRoot,
nullifier,
feedback,
groupId,
points
);

semaphore.validateProof(groupId, proof);
}
}
74 changes: 74 additions & 0 deletions packages/cli-template-contracts-foundry/test/Feedback.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {Test} from "forge-std/Test.sol";
import {ISemaphore} from "@semaphore/contracts/interfaces/ISemaphore.sol";
import {ISemaphoreGroups} from "@semaphore/contracts/interfaces/ISemaphoreGroups.sol";
import {Feedback} from "../src/Feedback.sol";
import {DeployFeedback} from "../script/DeployFeedback.s.sol";

contract FeedbackTest is Test {
event MemberAdded(uint256 indexed groupId, uint256 index, uint256 identityCommitment, uint256 merkleTreeRoot);

Feedback internal feedbackContract;
ISemaphore internal semaphoreContract;
ISemaphoreGroups internal semaphoreGroups;
uint256 internal groupId;

function setUp() external {
DeployFeedback deployFeedback = new DeployFeedback();
(address feedbackAddress, address semaphoreAddress, ) = deployFeedback.run();
feedbackContract = Feedback(feedbackAddress);
semaphoreContract = ISemaphore(semaphoreAddress);
semaphoreGroups = ISemaphoreGroups(semaphoreAddress);
groupId = feedbackContract.groupId();
}

function testGroupCreatedInConstructor() public view {
uint256 groupCount = semaphoreContract.groupCounter();
assertEq(groupCount, 1);
}

function testJoinGroup() public {
// The commitment below is generated with private key of the first account in Anvil
uint256 identityCommitment = 15072455385723004728391568434269917452175057560864330595979104241296826134229;

// Test: expect an event emitted. Check for all event topics and data
vm.expectEmit(true, true, true, true);
emit MemberAdded(groupId, 0, identityCommitment, identityCommitment);

feedbackContract.joinGroup(identityCommitment);
}

function testSendFeedback() public {
uint256[] memory commitments = new uint256[](2);
commitments[0] = uint256(11005642493773047649202648265396872197147567800455247120861783398111750817516);
commitments[1] = uint256(14473821761500463903284857947161896352613497175238126022206384102438097355186);

for (uint256 i = 0; i < commitments.length; ++i) {
feedbackContract.joinGroup(commitments[i]);
}

uint256 merkleTreeDepth = 1;
uint256 merkleTreeRoot = semaphoreGroups.getMerkleTreeRoot(groupId);
uint256 feedback = uint256(bytes32("Hello World"));

// These values are computed by running through @semaphore-protocol/circuits
uint256 nullifier = 14622092170088252518938850323258916742048811914834592843410744760450844885096;
uint256[8] memory points = [
2004484873491928515306456072357737929124240734208600886081152392890959117520,
21291026142870585364296731900941597996672838511394659364623185352043543529323,
4657264777014371046112557309523098953851041383509685591373847255581509612788,
6904165961903336246592681066375875983213983935764940579845010085396463328555,
1952750241178995674697344628236393389729638396609772141225880353616301956443,
106937615136633409337870509099767689510837462832227699340906789167349502398,
13080722838047436988558418790480431472161933638137155324683844808531903905810,
2547578906197450986657523555784319153413167960139250957065929818900731634820
];

vm.expectEmit(true, true, true, true);
emit ISemaphore.ProofValidated(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, feedback, groupId, points);

feedbackContract.sendFeedback(merkleTreeDepth, merkleTreeRoot, nullifier, feedback, points);
}
}
Loading

0 comments on commit 4cc6980

Please sign in to comment.