mirror of
https://github.com/semaphore-protocol/semaphore.git
synced 2026-01-11 15:48:12 -05:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fadcf19206 | ||
|
|
3be17268ab | ||
|
|
82cdc60af6 | ||
|
|
6c9ede6931 | ||
|
|
e6576cdc47 | ||
|
|
c07dc88490 | ||
|
|
67060dd412 | ||
|
|
a4e540d8f4 | ||
|
|
79976f33cb | ||
|
|
822530f2cf | ||
|
|
b3f862979d | ||
|
|
06e11d5c34 | ||
|
|
88d4470b11 | ||
|
|
bb1c6984b2 | ||
|
|
5841327477 | ||
|
|
eab3ab30c6 | ||
|
|
cd6dc38f9e | ||
|
|
3cb1b5757d | ||
|
|
a8db8393c1 | ||
|
|
391b571c31 | ||
|
|
4c2769099f | ||
|
|
29cabb49d6 | ||
|
|
48b0694586 | ||
|
|
28684fdb1a | ||
|
|
49a16635d8 | ||
|
|
4bfe6d8791 | ||
|
|
a3d97795fe | ||
|
|
4c8d297902 | ||
|
|
fdbadf5b71 | ||
|
|
4496eee137 | ||
|
|
215a12e25c | ||
|
|
87331114c1 | ||
|
|
0d41562dad | ||
|
|
c435712656 | ||
|
|
7d48311474 | ||
|
|
5ef73e2819 | ||
|
|
de7bdd6d17 | ||
|
|
21c2739f19 | ||
|
|
1ed170d0db | ||
|
|
bc041486b0 | ||
|
|
5db1bccb84 | ||
|
|
b2da0a685a | ||
|
|
9329eed754 | ||
|
|
75563ee0d5 | ||
|
|
368bbd4bcd |
@@ -26,5 +26,13 @@
|
||||
"no-console": ["warn", { "allow": ["info", "warn", "error"] }],
|
||||
"@typescript-eslint/lines-between-class-members": "off",
|
||||
"no-param-reassign": "off"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["./scripts/*"],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.github/workflows/production.yml
vendored
2
.github/workflows/production.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
sudo apt-get update && sudo apt-get install -y wget nlohmann-json3-dev libgmp-dev nasm g++ build-essential
|
||||
|
||||
- name: Setup Circom
|
||||
run: wget https://github.com/iden3/circom/releases/latest/download/circom-linux-amd64 && sudo mv ./circom-linux-amd64 /usr/bin/circom && sudo chmod +x /usr/bin/circom
|
||||
run: sudo wget https://github.com/iden3/circom/releases/download/v2.1.9/circom-linux-amd64 -O /usr/bin/circom && sudo chmod +x /usr/bin/circom
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
2
.github/workflows/pull-requests.yml
vendored
2
.github/workflows/pull-requests.yml
vendored
@@ -111,7 +111,7 @@ jobs:
|
||||
run: |
|
||||
sudo rm /etc/apt/sources.list.d/microsoft-prod.list
|
||||
sudo apt-get update && sudo apt-get install -y wget nlohmann-json3-dev libgmp-dev nasm g++ build-essential
|
||||
wget https://github.com/iden3/circom/releases/latest/download/circom-linux-amd64 && sudo mv ./circom-linux-amd64 /usr/bin/circom && sudo chmod +x /usr/bin/circom
|
||||
sudo wget https://github.com/iden3/circom/releases/download/v2.1.9/circom-linux-amd64 -O /usr/bin/circom && sudo chmod +x /usr/bin/circom
|
||||
yarn workspace @semaphore-protocol/group build
|
||||
yarn workspace @semaphore-protocol/identity build
|
||||
yarn workspace @semaphore-protocol/proof build
|
||||
|
||||
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
@@ -17,6 +17,16 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install soldeer
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: soldeer
|
||||
- name: Store soldeer login credential
|
||||
env:
|
||||
SOLDEER_TOKEN: ${{ secrets.SOLDEER_TOKEN }}
|
||||
run: |
|
||||
echo "$SOLDEER_TOKEN" > "$GITHUB_WORKSPACE"/soldeer_login
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -37,6 +47,7 @@ jobs:
|
||||
run: yarn version:publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
SOLDEER_LOGIN_FILE: ${{ github.workspace }}/soldeer_login
|
||||
|
||||
- run: yarn version:release
|
||||
env:
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -94,3 +94,5 @@ typechain-types
|
||||
|
||||
# Other
|
||||
snark-artifacts
|
||||
|
||||
*.zip
|
||||
|
||||
1
.soldeerignore
Normal file
1
.soldeerignore
Normal file
@@ -0,0 +1 @@
|
||||
package.json
|
||||
@@ -53,7 +53,7 @@
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://semaphore.pse.dev/discord">
|
||||
<a href="https://semaphore.pse.dev/telegram">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
<span> | </span>
|
||||
@@ -374,5 +374,5 @@ yarn version:bump <version>
|
||||
# e.g. yarn version:bump 2.0.0
|
||||
```
|
||||
|
||||
It will create a commit and a git tag that will need to pushed on the main branch. A workflow will be triggered and will
|
||||
It will create a commit and a git tag that will need to be pushed on the main branch. A workflow will be triggered and will
|
||||
publish the Semaphore packages on [npm](https://www.npmjs.com/) and release a new version on Github with its changelogs automatically.
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://semaphore.pse.dev/discord">
|
||||
<a href="https://semaphore.pse.dev/telegram">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
@@ -67,7 +67,7 @@ const config: Config = {
|
||||
announcementBar: {
|
||||
id: "semaphore-v4-beta",
|
||||
content:
|
||||
'<b>Semaphore V4-beta is out 🎉 <a href="/getting-started">Try it out</a> and contribute to the <a href="/trusted-setup">Trusted Setup ceremony</a>. Let us know for any feedback on <a href="https://semaphore.pse.dev/discord" target="_blank">Discord</a> or <a href="https://github.com/orgs/semaphore-protocol/discussions" target="_blank">Github</a>!</b>',
|
||||
'<b><a href="https://github.com/semaphore-protocol/semaphore/releases/tag/v4.0.0" target="_blank">Semaphore V4</a> is out 🎉 <a href="/getting-started">Try it out</a> and let us know if you have any feedback on <a href="https://semaphore.pse.dev/telegram" target="_blank">Telegram</a> or <a href="https://github.com/orgs/semaphore-protocol/discussions" target="_blank">Github</a>!</b>',
|
||||
backgroundColor: "#dde6fc",
|
||||
textColor: "#000000"
|
||||
},
|
||||
|
||||
@@ -386,7 +386,7 @@
|
||||
"message": "Connect"
|
||||
},
|
||||
"footer.right.connect.link1": {
|
||||
"message": "Discord"
|
||||
"message": "Telegram"
|
||||
},
|
||||
"footer.right.connect.link2": {
|
||||
"message": "X (Twitter)"
|
||||
|
||||
@@ -386,7 +386,7 @@
|
||||
"message": "Conecta con nosotros"
|
||||
},
|
||||
"footer.right.connect.link1": {
|
||||
"message": "Discord"
|
||||
"message": "Telegram"
|
||||
},
|
||||
"footer.right.connect.link2": {
|
||||
"message": "X (Twitter)"
|
||||
|
||||
@@ -14,7 +14,7 @@ También proporciona un mecanismo simple para evitar la doble señalización, lo
|
||||
|
||||
## ¿Dónde puedo hacer preguntas sobre Semaphore?
|
||||
|
||||
Puede hacer preguntas sobre Semaphore en [Discord](https://semaphore.pse.dev/discord) o abriendo un [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions).
|
||||
Puede hacer preguntas sobre Semaphore en [Telegram](https://semaphore.pse.dev/telegram) o abriendo un [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions).
|
||||
|
||||
## ¿Por qué las identidades requieren tanto `identity trapdoor` como `identity nullifier`?
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import TabItem from "@theme/TabItem"
|
||||
|
||||
# Solución de problemas
|
||||
|
||||
Si estas sugerencias no funcionan, no dude en preguntar en las [Semaphore Discussions](https://github.com/semaphore-protocol/semaphore/discussions) o en el canal `dev-chat` en el [Semaphore Discord](https://semaphore.pse.dev/discord).
|
||||
Si estas sugerencias no funcionan, no dude en preguntar en las [Semaphore Discussions](https://github.com/semaphore-protocol/semaphore/discussions) o en el canal [Semaphore Telegram](https://semaphore.pse.dev/telegram).
|
||||
|
||||
## Usando Semaphore en the frontend
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"@docusaurus/core": "3.1.1",
|
||||
"@docusaurus/preset-classic": "3.1.1",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-plugin-sass": "^0.2.5",
|
||||
|
||||
@@ -32,7 +32,7 @@ function Footer() {
|
||||
id: "footer.right.connect.title"
|
||||
})}
|
||||
</h3>
|
||||
<Link href="https://semaphore.pse.dev/discord" target="_blank">
|
||||
<Link href="https://semaphore.pse.dev/telegram" target="_blank">
|
||||
{translate({
|
||||
id: "footer.right.connect.link1"
|
||||
})}
|
||||
|
||||
@@ -21,7 +21,7 @@ The first external nullifier will be added as an external nullifier to the
|
||||
contract, and this external nullifier will be active once the deployment
|
||||
completes.
|
||||
|
||||
## Add, deactivate, or reactivate external nullifiiers
|
||||
## Add, deactivate, or reactivate external nullifiers
|
||||
|
||||
**Contract ABI**:
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ An identity is comprised of the following information:
|
||||
|
||||
1. An [EdDSA](https://en.wikipedia.org/wiki/EdDSA) private key. Note that it is
|
||||
_not_ an Ethereum private key.
|
||||
2. An identity nullifier, whih is a random 32-byte value.
|
||||
3. An identity trapdoor, whih is a random 32-byte value.
|
||||
2. An identity nullifier, which is a random 32-byte value.
|
||||
3. An identity trapdoor, which is a random 32-byte value.
|
||||
|
||||
An identity commitment is the Pedersen hash of:
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ It returns an object as such:
|
||||
- `msg`: The hash of the external nullifier and the signal hash
|
||||
- `signature`: The signature on the above msg.
|
||||
- `tree`: The Merkle tree object after it has been updated with the identity commitment
|
||||
- `identityPath`: The Merkle path to the identity commmitment
|
||||
- `identityPath`: The Merkle path to the identity commitment
|
||||
- `identityPathIndex`: The leaf index of the identity commitment
|
||||
- `identityPathElements`: The elements along the above Merkle path
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ It also provides a simple mechanism to prevent double-signaling, which means you
|
||||
|
||||
## Where can I ask questions about Semaphore?
|
||||
|
||||
You can ask questions about Semaphore on [Discord](https://semaphore.pse.dev/discord) or by opening a [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions).
|
||||
You can ask questions about Semaphore on [Telegram](https://semaphore.pse.dev/telegram) or by opening a [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions).
|
||||
|
||||
## Why do identities require both the `identity trapdoor` and the `identity nullifier`?
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import TabItem from "@theme/TabItem"
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
If these suggestions do not work, feel free to ask in the [Semaphore Discussions](https://github.com/semaphore-protocol/semaphore/discussions) or in the `dev-chat` channel in the [Semaphore Discord](https://semaphore.pse.dev/discord).
|
||||
If these suggestions do not work, feel free to ask in the [Semaphore Discussions](https://github.com/semaphore-protocol/semaphore/discussions) or in the [Semaphore Telegram](https://semaphore.pse.dev/telegram).
|
||||
|
||||
## Using Semaphore in the frontend
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Trusted Setup
|
||||
|
||||
gm, everyone 😎 we are excited to announce the upcoming Multi-Party Computation (MPC) Phase 2 Trusted Setup ceremony for the Semaphore V4 circuit - this is crucial for establishing a robust security foundation for the cryptographic protocol 🎉
|
||||
|
||||
The ceremony will take place from **June 10** to **July 10**. If all goes to plan, finalization should take place on **July 15** with the announcement of the final beacon on **July 12**.
|
||||
|
||||
## Securing Semaphore V4
|
||||
|
||||
To contribute to this ceremony, you will just need your browser!
|
||||
|
||||
1. Visit [ceremony.pse.dev](https://ceremony.pse.dev/projects/Semaphore%20V4%20Ceremony).
|
||||
2. Login and associate your **Github** account.
|
||||
3. Hit the `contribute` button and wait for your turn.
|
||||
|
||||
nb. you will find your contribution certificate on your GitHub gists - and, if all goes wrong or you feel lost, there are instructions on site or post a message on Semaphore / PSE discord.
|
||||
|
||||
## What You Need to Know About the Ceremony
|
||||
|
||||
### Your Role
|
||||
|
||||
Many zero-knowledge proof systems, including those based on the Groth16 scheme, require this layer of randomness, often referred to as "toxic waste” which must remain unknown to anyone to maintain the integrity of the zero-knowledge proof system. Trusted setups rely on a 1 of N honest participant assumption. As long as just one participant actually discards their “toxic waste”, the proof system will be secure. You can be that one participant by providing your unique entropy with your contribution, making the ceremony unpredictable and unbiased, safeguarding the entire process against potential vulnerabilities.
|
||||
|
||||
### Why It Matters
|
||||
|
||||
Trusted setups are crucial as they generate a set of parameters necessary to initiate SNARK-based systems. Through a series of computations performed by various participants. This sequence involves downloading previous contributions, adding generated randomness, and uploading the results of your contribution. These contributions are then integrated into the final artifacts crucial for proof generation/verification.
|
||||
|
||||
### Semaphore Circuit
|
||||
|
||||
The [Semaphore circuit](https://github.com/semaphore-protocol/semaphore/blob/main/packages/circuits/src/semaphore.circom) centered around the creation of the _Semaphore identity_ and _identity commitment_, includes verification processes, and facilitates the generation of the _nullifier_. We are going to support `MAX_DEPTH` from 1 to 32 - therefore you will have to contribute to 32 variants of the same circuit. Since the constraints will range from 2k to less than 10k with very small artifacts size (≤ 8mb x contribution), the waiting and contribution time shouldn’t be much!
|
||||
|
||||
### Transparency and Fairness
|
||||
|
||||
We are committed to transparency on ceremony setup, execution, finalization, and later verification. Our primary goal is to **engage as many contributors as possible** to ensure the circuit is **secure** and **production-ready**. To this end, the ceremony is designed to _maximize contributor inclusion_, monitor & troubleshoot whenever is needed, _lower the entry barriers_, _making contributiong as effortless as possible_. A key step towards achieving these goals is running the ceremony w/ [p0tion](https://github.com/privacy-scaling-explorations/p0tion): an in-house developed, open-source, battle-tested tool that is fully equipped to meet our needs.
|
||||
|
||||
### Ceremony Settings
|
||||
|
||||
To protect the ceremony from sybils, in order to contribute you must have a GitHub account such that you have: 1 public repository, at least 1 follower, following at least 5 other accounts and, your account is at least 1 month old. While to protect from fake contributors or people hanging due to connection/machine resources, we are going to set a 10 minutes time-window on contributions (+ 1 hour verification) - after this amount of time, you will be kicked out and will have to wait **1 day** before you can contribute again.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If you have been idle longer than expected, it may be that the current contributor has been blocked for some reason. Do not worry, the maximum wait in this case is one hour, after which you will be able to continue contributing.
|
||||
|
||||
### Learn more about Trusted Setups
|
||||
|
||||
- [How Do Trusted Setups Work? - Vitalik](https://vitalik.eth.limo/general/2022/03/14/trustedsetup.html)
|
||||
- [p0tion FAQs](https://p0tion.super.site/faqs#block-cebca23ebb514c2ea096ad44d4833356)
|
||||
@@ -17,3 +17,4 @@ Semaphore is the work of several people, for a complete list of contributors you
|
||||
- [LauNaMu](https://github.com/0xyNaMu)
|
||||
- [0xjei](https://github.com/0xjei)
|
||||
- [Mari Poveda](https://github.com/maripoveda)
|
||||
- [Gauthier](https://github.com/sripwoud)
|
||||
@@ -6,7 +6,7 @@ sidebar_position: 11
|
||||
|
||||
## Where can I ask questions about Semaphore?
|
||||
|
||||
You can ask questions about Semaphore on [Discord](https://semaphore.pse.dev/discord) or by opening a [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions). The most frequent questions will be listed below.
|
||||
You can ask questions about Semaphore on [Telegram](https://semaphore.pse.dev/telegram) or by opening a [Semaphore Discussion](https://github.com/semaphore-protocol/semaphore/discussions). The most frequent questions will be listed below.
|
||||
|
||||
## Why should I prevent proofs from being verified twice?
|
||||
|
||||
@@ -7,13 +7,7 @@ import TabItem from "@theme/TabItem"
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
If these suggestions do not work, feel free to ask for more help and support on [Github Discussions](https://github.com/semaphore-protocol/semaphore/discussions) or [Discord](https://semaphore.pse.dev/discord) ("dev-chat" channel).
|
||||
|
||||
## Creating a Group
|
||||
|
||||
When you create a group and the transaction is reverted, make sure that the group id you are using does not exist on the network you are using.
|
||||
|
||||
To check that, you can use the [Semaphore CLI](https://github.com/semaphore-protocol/semaphore/tree/main/packages/cli) with the command `get-groups` and the network you are using and then, make sure that your group id is not part of that list. You can also use the [Semaphore explorer](https://explorer.semaphore.pse.dev/).
|
||||
If these suggestions do not work, feel free to ask for more help and support on [Github Discussions](https://github.com/semaphore-protocol/semaphore/discussions) or [Telegram](https://semaphore.pse.dev/telegram).
|
||||
|
||||
## Transaction reverted when using the same nullifier
|
||||
|
||||
@@ -38,6 +38,10 @@ In addition to circuits,
|
||||
Semaphore provides [Solidity contracts](https://github.com/semaphore-protocol/semaphore/tree/main/packages/contracts)
|
||||
and [JavaScript libraries](https://github.com/semaphore-protocol/semaphore/tree/main#-packages) that allow developers to generate zero-knowledge proofs and verify them with minimal effort.
|
||||
|
||||
## Trusted Setup Ceremony
|
||||
|
||||
The [secure parameters](https://snark-artifacts.pse.dev) for generating valid proofs with Semaphore circuits were generated in a [Trusted Setup Ceremony](https://ceremony.pse.dev/projects/Semaphore%20V4%20Ceremony) that was completed with over 400 participants on [13 July 2024](https://etherscan.io/block/20300394).
|
||||
|
||||
### Audits
|
||||
|
||||
| Version | Auditors | Report | Scope |
|
||||
@@ -46,7 +50,3 @@ and [JavaScript libraries](https://github.com/semaphore-protocol/semaphore/tree/
|
||||
| v2.5.0 | [PSE](https://pse.dev/) | [Semaphore_2.5.0_Audit.pdf](https://semaphore.pse.dev/Semaphore_2.5.0_Audit.pdf) | `contracts`, `libraries` |
|
||||
| v3.0.0 | [Veridise](https://veridise.com/) | [Semaphore_3.0.0_Audit.pdf](https://semaphore.pse.dev/Semaphore_3.0.0_Audit.pdf) | `circuits`, `contracts` |
|
||||
| v4.0.0 | [PSE](https://pse.dev/) | [Semaphore_4.0.0_Audit.pdf](https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf) | `circuits`, `contracts`, `libraries` |
|
||||
|
||||
:::caution
|
||||
Semaphore V4 is in early testing and might have bugs. Please, don't use it in production.
|
||||
:::
|
||||
@@ -1 +1 @@
|
||||
["V4-beta", "V3", "V2", "V1"]
|
||||
["V4", "V3", "V2", "V1"]
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://semaphore.pse.dev/discord">
|
||||
<a href="https://semaphore.pse.dev/telegram">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
</h4>
|
||||
@@ -42,15 +42,21 @@
|
||||
|
||||
## Networks
|
||||
|
||||
| Semaphore version | Sepolia | Polygon Mumbai | Optimism Sepolia | Arbitrum Sepolia | Arbitrum One | Polygon Amoy |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| v2.0 | N/A | N/A | N/A | N/A | [semaphore-protocol/arbitrum](https://thegraph.com/hosted-service/subgraph/semaphore-protocol/arbitrum) | N/A |
|
||||
| v2.5 | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
| v2.6 | N/A | N/A | N/A | N/A | [semaphore-protocol/arbitrum-86337c](https://thegraph.com/hosted-service/subgraph/semaphore-protocol/arbitrum-86337c) | N/A |
|
||||
| v3.0 - v3.1 | N/A | N/A | N/A | N/A | [semaphore-protocol/arbitrum-72dca3](https://thegraph.com/hosted-service/subgraph/semaphore-protocol/arbitrum-72dca3) | N/A |
|
||||
| >= v3.2 | [semaphore-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-sepolia/v3.6.1) | [semaphore-mumbai](https://api.studio.thegraph.com/query/14377/semaphore-mumbai/v3.6.1) | N/A | N/A | [semaphore-arbitrum](https://api.studio.thegraph.com/query/14377/semaphore-arbitrum/v3.6.1) | N/A |
|
||||
| v4.0.0-beta | [semaphore-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-sepolia/v4.0.0-beta) | [semaphore-matic-mumbai](https://api.studio.thegraph.com/query/14377/semaphore-matic-mumbai/v4.0.0-beta) | [semaphore-optimism-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-optimism-sepolia/v4.0.0-beta) | [semaphore-arbitrum-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-arbitrum-sepolia/v4.0.0-beta) | N/A | N/A |
|
||||
| >= v4.0.0-beta.17 | [semaphore-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-sepolia/v4.0.0-beta.17) | N/A | [semaphore-optimism-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-optimism-sepolia/v4.0.0-beta.17) | [semaphore-arbitrum-sepolia](https://api.studio.thegraph.com/query/14377/semaphore-arbitrum-sepolia/v4.0.0-beta.17) | N/A | [semaphore-matic-amoy](https://api.studio.thegraph.com/query/14377/semaphore-matic-amoy/v4.0.0-beta.17) |
|
||||
You can access any subgraph supported by Semaphore with the following URL: https://api.studio.thegraph.com/query/14377/semaphore-<network-name>/v4.0.0-beta.17.
|
||||
|
||||
Supported networks:
|
||||
|
||||
- `sepolia`
|
||||
- `optimism`
|
||||
- `optimism-sepolia`
|
||||
- `arbitrum-one`
|
||||
- `arbitrum-sepolia`
|
||||
- `matic`
|
||||
- `polygon-amoy`
|
||||
- `base-sepolia`
|
||||
- `base`
|
||||
- `linea-sepolia`
|
||||
- `linea`
|
||||
|
||||
## 🛠 Install
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"dependencies": {
|
||||
"@graphprotocol/graph-cli": "0.78.0",
|
||||
"@graphprotocol/graph-ts": "0.35.1",
|
||||
"@semaphore-protocol/utils": "4.0.0"
|
||||
"@semaphore-protocol/utils": "workspace:packages/utils"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mustache": "^4.2.2",
|
||||
|
||||
@@ -6,8 +6,20 @@ const network = process.argv.at(2)
|
||||
|
||||
const template = readFileSync("./subgraph.template.yaml", "utf-8")
|
||||
|
||||
function mapNetwork(n) {
|
||||
if (n === "matic-amoy") {
|
||||
return "polygon-amoy"
|
||||
}
|
||||
|
||||
if (n === "arbitrum") {
|
||||
return "arbitrum-one"
|
||||
}
|
||||
|
||||
return network
|
||||
}
|
||||
|
||||
const subgraph = Mustache.render(template, {
|
||||
network: network === "matic-amoy" ? "polygon-amoy" : network,
|
||||
network: mapNetwork(network),
|
||||
...getDeployedContract(network)
|
||||
})
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://semaphore.pse.dev/discord">
|
||||
<a href="https://semaphore.pse.dev/telegram">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
@@ -32,19 +32,18 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
<body suppressHydrationWarning>
|
||||
<Providers>
|
||||
<Banner>
|
||||
Semaphore V4
|
||||
<Link
|
||||
_hover={{
|
||||
textDecoration: "underline",
|
||||
textDecorationColor: "primary.600"
|
||||
}}
|
||||
href="https://ceremony.pse.dev/projects/Semaphore%20V4%20Ceremony"
|
||||
href="https://github.com/semaphore-protocol/semaphore/releases/tag/v4.0.0"
|
||||
ml="1"
|
||||
isExternal
|
||||
>
|
||||
<b>Trusted Setup</b>
|
||||
<b>Semaphore V4</b>
|
||||
</Link>{" "}
|
||||
ceremony is open for contributions until <b>July 10</b>.
|
||||
has been released 🚀
|
||||
</Banner>
|
||||
<Navbar />
|
||||
<Container maxW="1440px" px={{ base: "5", md: "10" }}>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Box, Button, Card, CardBody, HStack, Heading, Image, Link, Stack, Text, VStack } from "@chakra-ui/react"
|
||||
import NextLink from "next/link"
|
||||
import { Sora } from "next/font/google"
|
||||
import NextLink from "next/link"
|
||||
import Carousel from "../components/Carousel"
|
||||
import ProjectCard from "../components/ProjectCard"
|
||||
import events from "../data/events.json"
|
||||
import allProjects from "../data/projects.json"
|
||||
import IconDiscord from "../icons/IconDiscord"
|
||||
import IconTelegram from "../icons/IconTelegram"
|
||||
import HRoadmap from "@/components/HRoadmap"
|
||||
import VRoadmap from "@/components/VRoadmap"
|
||||
|
||||
const sora = Sora({
|
||||
subsets: ["latin"]
|
||||
@@ -220,6 +222,35 @@ export default function Home() {
|
||||
</Card>
|
||||
</HStack>
|
||||
|
||||
<VStack mb="32" spacing="32">
|
||||
<VStack w="full" maxW="1110px">
|
||||
<Heading fontSize={{ base: "30px", md: "44px" }} pb="90px">
|
||||
2024 Roadmap
|
||||
</Heading>
|
||||
|
||||
<HStack display={{ base: "none", md: "flex" }} w="full" mt="60px">
|
||||
<HRoadmap />
|
||||
</HStack>
|
||||
|
||||
<VStack display={{ base: "flex", md: "none" }}>
|
||||
<VRoadmap />
|
||||
</VStack>
|
||||
</VStack>
|
||||
|
||||
<VStack maxW="650" align="center" spacing="8">
|
||||
<Heading fontSize={{ base: "30px", md: "44px" }}>Join the Semaphore community</Heading>
|
||||
<Text fontSize={{ base: "16px", md: "18px" }} textAlign="center">
|
||||
Ask questions, suggest ideas, stay up-to-date, and meet other people building privacy
|
||||
applications with Zero Knowledge.
|
||||
</Text>
|
||||
<Link href="https://semaphore.pse.dev/telegram" isExternal>
|
||||
<Button leftIcon={<IconTelegram />} size="lg">
|
||||
Telegram
|
||||
</Button>
|
||||
</Link>
|
||||
</VStack>
|
||||
</VStack>
|
||||
|
||||
<VStack justify="center" spacing="40" py="32" position="relative">
|
||||
<Box
|
||||
zIndex="-1"
|
||||
@@ -239,27 +270,16 @@ export default function Home() {
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Stack direction={{ base: "column", md: "row" }} px={{ base: "0", md: "12" }} spacing="32">
|
||||
<VStack maxW="450" align="left" spacing="8">
|
||||
<Heading fontSize={{ base: "30px", md: "44px" }}>Join the Semaphore community</Heading>
|
||||
<Text fontSize={{ base: "16px", md: "18px" }}>
|
||||
Ask questions, suggest ideas, stay up-to-date, and meet other people building privacy
|
||||
applications with Zero Knowledge.
|
||||
</Text>
|
||||
<Link href="https://semaphore.pse.dev/discord" isExternal>
|
||||
<Button leftIcon={<IconDiscord />} size="lg">
|
||||
Discord
|
||||
</Button>
|
||||
</Link>
|
||||
</VStack>
|
||||
<Stack direction={{ base: "column", md: "row" }} px={{ base: "0", md: "12" }} w="full">
|
||||
<Box flex="1" />
|
||||
|
||||
<Card
|
||||
bg="inherit"
|
||||
flex="1"
|
||||
bg="darkBlue"
|
||||
color="white"
|
||||
backdropFilter="blur(4px)"
|
||||
borderRadius="18px"
|
||||
border="1px"
|
||||
borderColor="white"
|
||||
borderColor="text.900"
|
||||
padding="50px"
|
||||
>
|
||||
<CardBody padding="0">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Divider, Heading, HStack, Link, Stack, Text, VStack } from "@chakra-ui/
|
||||
import Image from "next/image"
|
||||
import NextLink from "next/link"
|
||||
import IconArrowUpRight from "../icons/IconArrowUpRight"
|
||||
import IconDiscord from "../icons/IconDiscord"
|
||||
import IconTelegram from "../icons/IconTelegram"
|
||||
import IconThumbsUp from "../icons/IconThumbsUp"
|
||||
import IconX from "@/icons/IconX"
|
||||
|
||||
@@ -59,11 +59,11 @@ export default function Footer() {
|
||||
<Divider />
|
||||
<VStack spacing="5">
|
||||
<HStack spacing="5">
|
||||
<Link href="https://semaphore.pse.dev/discord" isExternal>
|
||||
<Link href="https://semaphore.pse.dev/telegram" isExternal>
|
||||
<HStack>
|
||||
<IconDiscord boxSize={{ base: "16px", md: "24px" }} />
|
||||
<IconTelegram boxSize={{ base: "16px", md: "24px" }} />
|
||||
<Heading fontSize={{ base: "14px", md: "18px" }} fontWeight="normal">
|
||||
Discord
|
||||
Telegram
|
||||
</Heading>
|
||||
</HStack>
|
||||
</Link>
|
||||
|
||||
58
apps/website/src/components/HRoadmap.tsx
Normal file
58
apps/website/src/components/HRoadmap.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Box, Text } from "@chakra-ui/react"
|
||||
import roadmap from "../data/roadmap.json"
|
||||
import IconInnerCheck from "../icons/IconInnerCheck"
|
||||
|
||||
export default function HRoadmap() {
|
||||
return roadmap.map((milestone, i) => (
|
||||
<Box
|
||||
key={milestone.name}
|
||||
borderBottomWidth={i % 2 === 0 ? "5px" : "0px"}
|
||||
borderTopWidth={i % 2 !== 0 ? "5px" : "0px"}
|
||||
borderLeftWidth="1px"
|
||||
borderColor="#1E46F2"
|
||||
transform={i % 2 === 0 ? "translateY(-74px)" : ""}
|
||||
h="80px"
|
||||
w="full"
|
||||
pos="relative"
|
||||
>
|
||||
{milestone.done ? (
|
||||
<IconInnerCheck
|
||||
pos="absolute"
|
||||
top={i % 2 !== 0 ? "-14px" : "inherit"}
|
||||
bottom={i % 2 === 0 ? "-14px" : "inherit"}
|
||||
left="-12px"
|
||||
bg="#1E46F2"
|
||||
borderRadius="50px"
|
||||
p="7px"
|
||||
w="24px"
|
||||
h="24px"
|
||||
color="white"
|
||||
/>
|
||||
) : (
|
||||
<Box
|
||||
pos="absolute"
|
||||
top={i % 2 !== 0 ? "-14px" : "inherit"}
|
||||
bottom={i % 2 === 0 ? "-14px" : "inherit"}
|
||||
left="-12px"
|
||||
bg="darkBlueBg"
|
||||
borderWidth="5px"
|
||||
borderColor="#1E46F2"
|
||||
borderRadius="50px"
|
||||
w="24px"
|
||||
h="24px"
|
||||
/>
|
||||
)}
|
||||
<Text
|
||||
pos="absolute"
|
||||
bg="darkBlueBg"
|
||||
fontSize="14px"
|
||||
py="5px"
|
||||
top={i % 2 === 0 ? "-35px" : "inherit"}
|
||||
bottom={i % 2 !== 0 ? "-35px" : "inherit"}
|
||||
left="-1px"
|
||||
>
|
||||
{milestone.name}
|
||||
</Text>
|
||||
</Box>
|
||||
))
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
} from "@chakra-ui/react"
|
||||
import Image from "next/image"
|
||||
import NextLink from "next/link"
|
||||
import IconDiscord from "../icons/IconDiscord"
|
||||
import IconTelegram from "../icons/IconTelegram"
|
||||
import IconMenu from "../icons/IconMenu"
|
||||
import IconThumbsUp from "../icons/IconThumbsUp"
|
||||
import NavbarLinks from "./NavbarLinks"
|
||||
@@ -71,11 +71,11 @@ export default function Navbar() {
|
||||
|
||||
<VStack w="full" justify="center" spacing="5">
|
||||
<HStack spacing="5">
|
||||
<Link href="https://semaphore.pse.dev/discord" isExternal>
|
||||
<Link href="https://semaphore.pse.dev/telegram" isExternal>
|
||||
<HStack>
|
||||
<IconDiscord boxSize={{ base: "16px", md: "24px" }} />
|
||||
<IconTelegram boxSize={{ base: "16px", md: "24px" }} />
|
||||
<Heading fontSize={{ base: "14px", md: "18px" }} fontWeight="normal">
|
||||
Discord
|
||||
Telegram
|
||||
</Heading>
|
||||
</HStack>
|
||||
</Link>
|
||||
|
||||
61
apps/website/src/components/VRoadmap.tsx
Normal file
61
apps/website/src/components/VRoadmap.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Box, Text } from "@chakra-ui/react"
|
||||
import roadmap from "../data/roadmap.json"
|
||||
import IconInnerCheck from "../icons/IconInnerCheck"
|
||||
|
||||
export default function VRoadmap() {
|
||||
return roadmap.map((milestone, i) => (
|
||||
<Box
|
||||
key={milestone.name}
|
||||
ml="-74px"
|
||||
borderLeftWidth={i % 2 === 0 ? "5px" : "0px"}
|
||||
borderRightWidth={i % 2 !== 0 ? "5px" : "0px"}
|
||||
borderTopWidth="1px"
|
||||
borderColor="#1E46F2"
|
||||
transform={i % 2 === 0 ? "translateX(74px)" : ""}
|
||||
h="80px"
|
||||
w="80px"
|
||||
pos="relative"
|
||||
>
|
||||
{milestone.done ? (
|
||||
<IconInnerCheck
|
||||
pos="absolute"
|
||||
right={i % 2 !== 0 ? "-14px" : "inherit"}
|
||||
left={i % 2 === 0 ? "-14px" : "inherit"}
|
||||
top="-12px"
|
||||
bg="#1E46F2"
|
||||
borderRadius="50px"
|
||||
p="7px"
|
||||
w="24px"
|
||||
h="24px"
|
||||
color="white"
|
||||
/>
|
||||
) : (
|
||||
<Box
|
||||
pos="absolute"
|
||||
right={i % 2 !== 0 ? "-14px" : "inherit"}
|
||||
left={i % 2 === 0 ? "-14px" : "inherit"}
|
||||
top="-12px"
|
||||
bg="darkBlueBg"
|
||||
borderWidth="5px"
|
||||
borderColor="#1E46F2"
|
||||
borderRadius="50px"
|
||||
w="24px"
|
||||
h="24px"
|
||||
/>
|
||||
)}
|
||||
<Text
|
||||
pos="absolute"
|
||||
bg="darkBlueBg"
|
||||
fontSize="14px"
|
||||
w="140px"
|
||||
px="16px"
|
||||
textAlign={i % 2 === 0 ? "left" : "right"}
|
||||
left={i % 2 === 0 ? "70px" : "inherit"}
|
||||
right={i % 2 !== 0 ? "70px" : "inherit"}
|
||||
top="-5px"
|
||||
>
|
||||
{milestone.name}
|
||||
</Text>
|
||||
</Box>
|
||||
))
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
[
|
||||
{
|
||||
"name": "Trusted Setup ceremony",
|
||||
"date": "June 10 - July 10, 2024",
|
||||
"description": "The Semaphore team will perform the Phase 2 MPC Trusted Setup ceremony to secure V4 circuit variants from 1 to 32 tree depths.",
|
||||
"link": "https://docs.semaphore.pse.dev/trusted-setup"
|
||||
},
|
||||
{
|
||||
"name": "ETHRome",
|
||||
"date": "Oct 4-6, 2024",
|
||||
"description": "Semaphore team will deliver an in-person talk and sponsor prizes for the hackathon.",
|
||||
"link": "https://www.ethrome.org/"
|
||||
"name": "DIF - Decentralized Identity Foundation",
|
||||
"date": "Oct 1 - Nov 4, 2024",
|
||||
"description": "Semaphore team will deliver a talk and sponsor prizes for the online hackathon.",
|
||||
"link": "https://identity.foundation/"
|
||||
},
|
||||
{
|
||||
"name": "Devcon",
|
||||
|
||||
@@ -11,15 +11,14 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Unirep",
|
||||
"tagline": "Private and nonrepudiable reputation system based on ZKP.",
|
||||
"categories": ["Reputation", "Identity", "Social"],
|
||||
"pse": true,
|
||||
"name": "Worldcoin",
|
||||
"categories": ["Identity"],
|
||||
"tagline": "A global digital currency offering universal access to a more inclusive financial system.",
|
||||
"pse": false,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"website": "https://developer.unirep.io",
|
||||
"github": "https://github.com/Unirep",
|
||||
"discord": "https://discord.gg/VzMMDJmYc5"
|
||||
"github": "https://github.com/worldcoin",
|
||||
"website": "https://worldcoin.org"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -33,6 +32,26 @@
|
||||
"website": "https://bandada.pse.dev"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ZkDemocracy",
|
||||
"categories": ["Infra", "Data"],
|
||||
"tagline": "ZkDemocracy is a ready-to-use anonymous voting system based on Semaphore.",
|
||||
"pse": false,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"github": "https://github.com/TheBojda/zkdemocracy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Super Secret ZK Ballot",
|
||||
"tagline": "A Solidity contract for anonymous voting.",
|
||||
"categories": ["Voting"],
|
||||
"pse": false,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"github": "https://github.com/dutragustavo/super-secret-zkballot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ZK Proof of Humanity",
|
||||
"tagline": "A project that allows humans, registered in Proof of Humanity, to prove their humanity without doxing.",
|
||||
@@ -106,20 +125,7 @@
|
||||
"icon": "",
|
||||
"links": {
|
||||
"website": "https://explorer.semaphore.pse.dev",
|
||||
"github": "https://github.com/semaphore-protocol/explorer",
|
||||
"discord": "https://semaphore.pse.dev/discord"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Semaphore Discord Bot",
|
||||
"tagline": "A Discord Bot for Semaphore",
|
||||
"categories": ["Development"],
|
||||
"pse": true,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"website": "https://discord.com/api/oauth2/authorize?client_id=1082429985496772628&permissions=1024&scope=bot",
|
||||
"github": "https://github.com/semaphore-protocol/discord-bot",
|
||||
"discord": "https://semaphore.pse.dev/discord"
|
||||
"github": "https://github.com/semaphore-protocol/explorer"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -487,14 +493,15 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Worldcoin",
|
||||
"categories": ["Identity"],
|
||||
"tagline": "A global digital currency offering universal access to a more inclusive financial system.",
|
||||
"pse": false,
|
||||
"name": "Unirep",
|
||||
"tagline": "Private and nonrepudiable reputation system based on ZKP.",
|
||||
"categories": ["Reputation", "Identity", "Social"],
|
||||
"pse": true,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"github": "https://github.com/worldcoin",
|
||||
"website": "https://worldcoin.org"
|
||||
"website": "https://developer.unirep.io",
|
||||
"github": "https://github.com/Unirep",
|
||||
"discord": "https://discord.gg/VzMMDJmYc5"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -537,5 +544,16 @@
|
||||
"github": "https://github.com/AsteriskDAO",
|
||||
"website": "https://ethglobal.com/showcase/asteriskdao-4hvhf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Pairwise",
|
||||
"tagline": "A fun pseudonymous way to signal in Retro Funding 4.",
|
||||
"categories": ["Retro Funding", "Public Goods", "Privacy", "Community"],
|
||||
"pse": false,
|
||||
"icon": "",
|
||||
"links": {
|
||||
"github": "https://github.com/GeneralMagicio/pairwise-RPGF4",
|
||||
"website": "https://pairwise.vote"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
38
apps/website/src/data/roadmap.json
Normal file
38
apps/website/src/data/roadmap.json
Normal file
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"name": "Launched New Website",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "V4 Audit",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "V4 Trusted Setup",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "V4 Stable Release",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "LeanIMT Paper",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "Support more Testnets/Mainnets",
|
||||
"done": true
|
||||
},
|
||||
{
|
||||
"name": "Documentation improvements",
|
||||
"done": false
|
||||
},
|
||||
{
|
||||
"name": "New Explorer",
|
||||
"done": false
|
||||
},
|
||||
{
|
||||
"name": "RLN extension",
|
||||
"done": false
|
||||
}
|
||||
]
|
||||
15
apps/website/src/icons/IconInnerCheck.tsx
Normal file
15
apps/website/src/icons/IconInnerCheck.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Icon, IconProps } from "@chakra-ui/react"
|
||||
import React from "react"
|
||||
|
||||
export default function IconInnerCheck(props: IconProps): JSX.Element {
|
||||
return (
|
||||
<Icon viewBox="0 0 9 7" {...props}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M7.84114 1.12297C8.23166 1.5135 8.23166 2.14666 7.84114 2.53718L3.84114 6.53718C3.45062 6.92771 2.81745 6.92771 2.42693 6.53718L0.426926 4.53718C0.0364021 4.14666 0.0364021 3.5135 0.426926 3.12297C0.817451 2.73245 1.45062 2.73245 1.84114 3.12297L3.13403 4.41586L6.42693 1.12297C6.81745 0.732447 7.45062 0.732447 7.84114 1.12297Z"
|
||||
fill="white"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
}
|
||||
13
apps/website/src/icons/IconTelegram.tsx
Normal file
13
apps/website/src/icons/IconTelegram.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Icon, IconProps } from "@chakra-ui/react"
|
||||
import React from "react"
|
||||
|
||||
export default function IconTelegram(props: IconProps): JSX.Element {
|
||||
return (
|
||||
<Icon viewBox="0 0 48 48" {...props}>
|
||||
<path
|
||||
d="M41.4193 7.30899C41.4193 7.30899 45.3046 5.79399 44.9808 9.47328C44.8729 10.9883 43.9016 16.2908 43.1461 22.0262L40.5559 39.0159C40.5559 39.0159 40.3401 41.5048 38.3974 41.9377C36.4547 42.3705 33.5408 40.4227 33.0011 39.9898C32.5694 39.6652 24.9068 34.7955 22.2086 32.4148C21.4531 31.7655 20.5897 30.4669 22.3165 28.9519L33.6487 18.1305C34.9438 16.8319 36.2389 13.8019 30.8426 17.4812L15.7331 27.7616C15.7331 27.7616 14.0063 28.8437 10.7686 27.8698L3.75342 25.7055C3.75342 25.7055 1.16321 24.0823 5.58815 22.459C16.3807 17.3729 29.6555 12.1786 41.4193 7.30899Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
}
|
||||
12
package.json
12
package.json
@@ -23,12 +23,12 @@
|
||||
"format": "concurrently -c auto -g -n prettier,embark \"prettier -c .\" \"yarn workspace semaphore-docs format\"",
|
||||
"format:write": "concurrently -c auto -g -n prettier,embark \"prettier -w .\" \"yarn workspace semaphore-docs format:write\"",
|
||||
"docs": "typedoc",
|
||||
"version:bump": "yarn workspaces foreach -A --no-private version -d ${0} && yarn version apply --all && yarn remove:stable-version-field && NO_HOOK=1 git commit -am \"chore: v${0}\" && git tag v${0}",
|
||||
"version:publish": "yarn build:libraries && yarn clean:cli-templates && yarn workspaces foreach -A --no-private npm publish --tolerate-republish --access public",
|
||||
"version:bump": "scripts/version.ts ${0}",
|
||||
"version:publish": "scripts/publish.ts",
|
||||
"version:release": "changelogithub",
|
||||
"clean": "ts-node scripts/clean-apps.ts && ts-node scripts/clean-packages.ts && yarn clean:cli-templates && rimraf node_modules",
|
||||
"clean:cli-templates": "ts-node scripts/clean-cli-templates.ts",
|
||||
"remove:stable-version-field": "ts-node scripts/remove-stable-version-field.ts && yarn format:write",
|
||||
"clean": "scripts/clean-apps.ts && scripts/clean-packages.ts && yarn clean:cli-templates && rimraf node_modules",
|
||||
"clean:cli-templates": "scripts/clean-cli-templates.ts",
|
||||
"remove:stable-version-field": "scripts/remove-stable-version-field.ts && yarn format:write",
|
||||
"precommit": "lint-staged",
|
||||
"postinstall": "husky && git config --local core.editor cat"
|
||||
},
|
||||
@@ -57,6 +57,7 @@
|
||||
"@types/glob": "^7.2.0",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20",
|
||||
"@types/semver": "^7",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
||||
"@typescript-eslint/parser": "^7.0.2",
|
||||
"changelogithub": "0.12.7",
|
||||
@@ -78,6 +79,7 @@
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "^3.2.5",
|
||||
"rimraf": "^5.0.5",
|
||||
"semver": "^7.6.2",
|
||||
"snarkjs": "0.7.4",
|
||||
"ts-jest": "^29.1.2",
|
||||
"ts-node": "^10.9.2",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
🔎 Issues
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://semaphore.pse.dev/discord">
|
||||
<a href="https://semaphore.pse.dev/telegram">
|
||||
🗣️ Chat & Support
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/circuits",
|
||||
"version": "4.0.0",
|
||||
"version": "4.4.2",
|
||||
"description": "Semaphore Circom circuits to generate zero-knowledge proofs.",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
@@ -30,9 +30,9 @@
|
||||
"devDependencies": {
|
||||
"@semaphore-protocol/core": "workspace:^",
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@zk-kit/baby-jubjub": "1.0.1",
|
||||
"circomkit": "^0.0.19",
|
||||
"@zk-kit/baby-jubjub": "1.0.3",
|
||||
"circomkit": "0.0.19",
|
||||
"mocha": "^10.2.0",
|
||||
"poseidon-lite": "^0.2.0"
|
||||
"poseidon-lite": "^0.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/cli-template-contracts-hardhat",
|
||||
"version": "4.0.0",
|
||||
"version": "4.4.2",
|
||||
"description": "Semaphore Hardhat template.",
|
||||
"license": "Unlicense",
|
||||
"files": [
|
||||
@@ -41,9 +41,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",
|
||||
"@semaphore-protocol/hardhat": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/core": "4.4.2",
|
||||
"@semaphore-protocol/hardhat": "4.4.2",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"@typechain/ethers-v6": "^0.5.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"@types/chai": "^4.2.0",
|
||||
@@ -71,7 +71,7 @@
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/contracts": "4.0.0"
|
||||
"@semaphore-protocol/contracts": "4.4.2"
|
||||
},
|
||||
"packageManager": "yarn@4.1.0"
|
||||
}
|
||||
|
||||
@@ -20,9 +20,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",
|
||||
"@semaphore-protocol/hardhat": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/core": "4.4.2",
|
||||
"@semaphore-protocol/hardhat": "4.4.2",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"@typechain/ethers-v6": "^0.5.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"@types/chai": "^4.2.0",
|
||||
@@ -50,7 +50,7 @@
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/contracts": "4.0.0"
|
||||
"@semaphore-protocol/contracts": "4.4.2"
|
||||
},
|
||||
"packageManager": "yarn@4.1.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
NEXT_PUBLIC_DEFAULT_NETWORK=localhost
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9
|
||||
NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
|
||||
NEXT_PUBLIC_GROUP_ID=0
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
NEXT_PUBLIC_DEFAULT_NETWORK=sepolia
|
||||
NEXT_PUBLIC_INFURA_API_KEY=abf67af1010b4b8d877e04244f1eac3d
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=
|
||||
NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS=0x1e0d7FF1610e480fC93BdEC510811ea2Ba6d7c2f
|
||||
NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK=https://api.defender.openzeppelin.com/actions/20fce2ae-844b-4ec0-a6a2-90a3350a9d2c/runs/webhook/303216d1-fa7d-4fca-8c5b-7ba1ba544fc7/2T7i9xrkZA5j37hoaQLUuw
|
||||
NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT=https://api.gelato.digital/relays/v2/sponsored-call
|
||||
NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID=11155111
|
||||
NEXT_PUBLIC_GROUP_ID=
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
@@ -7,3 +10,18 @@
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# Auto Generated PWA files
|
||||
public/sw.js
|
||||
public/workbox-*.js
|
||||
public/worker-*.js
|
||||
public/sw.js.map
|
||||
public/workbox-*.js.map
|
||||
public/worker-*.js.map
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
"internalType": "address",
|
||||
"name": "semaphoreAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_groupId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
@@ -92,8 +87,8 @@
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"bytecode": "0x608060405234801561001057600080fd5b5060405161083f38038061083f833981810160405281019061003291906101a8565b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060018190555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c96e71fb600154306040518363ffffffff1660e01b81526004016100d6929190610206565b600060405180830381600087803b1580156100f057600080fd5b505af1158015610104573d6000803e3d6000fd5b50505050505061022f565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061013f82610114565b9050919050565b61014f81610134565b811461015a57600080fd5b50565b60008151905061016c81610146565b92915050565b6000819050919050565b61018581610172565b811461019057600080fd5b50565b6000815190506101a28161017c565b92915050565b600080604083850312156101bf576101be61010f565b5b60006101cd8582860161015d565b92505060206101de85828601610193565b9150509250929050565b6101f181610172565b82525050565b61020081610134565b82525050565b600060408201905061021b60008301856101e8565b61022860208301846101f7565b9392505050565b6106018061023e6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea2646970667358221220f33606b2d5ad7c0dfc5d22afb43476e1974ea7fd160e1f28203a3e433f29cb4964736f6c63430008170033",
|
||||
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea2646970667358221220f33606b2d5ad7c0dfc5d22afb43476e1974ea7fd160e1f28203a3e433f29cb4964736f6c63430008170033",
|
||||
"bytecode": "0x608060405234801561001057600080fd5b506040516108473803806108478339818101604052810190610032919061017d565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635c3f3b60306040518263ffffffff1660e01b81526004016100cb91906101b9565b6020604051808303816000875af11580156100ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010e919061020a565b60018190555050610237565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061014a8261011f565b9050919050565b61015a8161013f565b811461016557600080fd5b50565b60008151905061017781610151565b92915050565b6000602082840312156101935761019261011a565b5b60006101a184828501610168565b91505092915050565b6101b38161013f565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b6000819050919050565b6101e7816101d4565b81146101f257600080fd5b50565b600081519050610204816101de565b92915050565b6000602082840312156102205761021f61011a565b5b600061022e848285016101f5565b91505092915050565b610601806102466000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea264697066735822122078569abd7f309f3107c4d19e9b4a4f4812522ccc5dc57c7ccbe2b06a5ba461b064736f6c63430008170033",
|
||||
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea264697066735822122078569abd7f309f3107c4d19e9b4a4f4812522ccc5dc57c7ccbe2b06a5ba461b064736f6c63430008170033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ const nextConfig = withPWA({
|
||||
})({
|
||||
env: {
|
||||
INFURA_API_KEY: process.env.INFURA_API_KEY,
|
||||
ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY
|
||||
ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY,
|
||||
GELATO_RELAYER_API_KEY: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/core": "4.0.0",
|
||||
"@semaphore-protocol/data": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/core": "4.4.2",
|
||||
"@semaphore-protocol/data": "4.4.2",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"ethers": "^6.11.1",
|
||||
"next": "14.1.0",
|
||||
"next-pwa": "^5.6.0",
|
||||
|
||||
@@ -3,26 +3,14 @@ import { NextRequest } from "next/server"
|
||||
import Feedback from "../../../../contract-artifacts/Feedback.json"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (typeof process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_DEFAULT_NETWORK in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.INFURA_API_KEY !== "string" && process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "localhost") {
|
||||
throw new Error("Please, define INFURA_API_KEY in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.ETHEREUM_PRIVATE_KEY !== "string") {
|
||||
throw new Error("Please, define ETHEREUM_PRIVATE_KEY in your .env file")
|
||||
}
|
||||
|
||||
const ethereumPrivateKey = process.env.ETHEREUM_PRIVATE_KEY
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
const infuraApiKey = process.env.INFURA_API_KEY
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string
|
||||
const infuraApiKey = process.env.NEXT_PUBLIC_INFURA_API_KEY as string
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
|
||||
const provider =
|
||||
ethereumNetwork === "localhost"
|
||||
|
||||
@@ -3,26 +3,14 @@ import { NextRequest } from "next/server"
|
||||
import Feedback from "../../../../contract-artifacts/Feedback.json"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (typeof process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_DEFAULT_NETWORK in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.INFURA_API_KEY !== "string" && process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "localhost") {
|
||||
throw new Error("Please, define INFURA_API_KEY in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.ETHEREUM_PRIVATE_KEY !== "string") {
|
||||
throw new Error("Please, define ETHEREUM_PRIVATE_KEY in your .env file")
|
||||
}
|
||||
|
||||
const ethereumPrivateKey = process.env.ETHEREUM_PRIVATE_KEY
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
const infuraApiKey = process.env.INFURA_API_KEY
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string
|
||||
const infuraApiKey = process.env.NEXT_PUBLIC_INFURA_API_KEY as string
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
|
||||
const provider =
|
||||
ethereumNetwork === "localhost"
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
:root {
|
||||
--slate100: #f1f5f9;
|
||||
--slate200: #e2e8f0;
|
||||
--slate300: #cbd5e1;
|
||||
--slate400: #94a3b8;
|
||||
--slate500: #64748b;
|
||||
--slate700: #334155;
|
||||
--blue200: #bfdbfe;
|
||||
--blue500: #3b82f6;
|
||||
--blue600: #2563eb;
|
||||
--blue700: #1d4ed8;
|
||||
--blue800: #1e40af;
|
||||
--blue900: #1e3a8a;
|
||||
--blue100: #dde6fc;
|
||||
--blue200: #c3d4fa;
|
||||
--blue300: #9abaf6;
|
||||
--blue400: #6a95f0;
|
||||
--blue500: #4771ea;
|
||||
--blue600: #3555df;
|
||||
--blue700: #2940cc;
|
||||
--blue800: #2735a6;
|
||||
--blue900: #253183;
|
||||
--blue950: #1b2050;
|
||||
--darkBlueBg: #00020d;
|
||||
--slate50: #f7f7f8;
|
||||
--slate100: #eeeef0;
|
||||
--slate200: #d9d9de;
|
||||
--slate300: #b8b9c1;
|
||||
--slate400: #92939e;
|
||||
--slate500: #747583;
|
||||
--slate600: #5e5f6b;
|
||||
--slate700: #4d4e57;
|
||||
--slate800: #42424a;
|
||||
--slate900: #3a3a40;
|
||||
--slate950: #26262b;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: "Outfit", sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -33,17 +44,30 @@ body {
|
||||
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
font-weight: 300;
|
||||
overflow-wrap: break-word;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.key-wrapper {
|
||||
padding-bottom: 1.5rem;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
max-width: 32rem;
|
||||
|
||||
max-width: 40vw;
|
||||
min-width: 35rem;
|
||||
margin: auto;
|
||||
padding: 1rem;
|
||||
|
||||
height: calc(100vh - 7rem - 1px);
|
||||
padding-bottom: 5rem;
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
}
|
||||
|
||||
@@ -57,28 +81,25 @@ p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.125rem;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: var(--slate500);
|
||||
opacity: 0.6;
|
||||
border: 0;
|
||||
border-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
width: 100%;
|
||||
border-color: var(--slate400);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
@@ -89,31 +110,44 @@ h3 {
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--blue500);
|
||||
color: var(--blue400);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--blue400);
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--blue800);
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px;
|
||||
border-radius: 100px;
|
||||
cursor: pointer;
|
||||
color: var(--slate100);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
transition: all 200ms linear;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
opacity: 0.9;
|
||||
font-weight: 400;
|
||||
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
|
||||
transition-duration: 200ms;
|
||||
padding-left: 18px !important;
|
||||
padding-right: 18px !important;
|
||||
height: 2.5rem;
|
||||
min-width: 2.5rem;
|
||||
font-size: 1rem;
|
||||
-webkit-padding-start: 1rem;
|
||||
padding-inline-start: 1rem;
|
||||
-webkit-padding-end: 1rem;
|
||||
padding-inline-end: 1rem;
|
||||
background: var(--blue500);
|
||||
color: white;
|
||||
background-image: linear-gradient(to right, var(--blue500), var(--blue800));
|
||||
transition-timing-function: linear;
|
||||
width: 100%;
|
||||
border: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 3rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: var(--blue900);
|
||||
background-color: var(--blue800);
|
||||
background-image: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
@@ -123,54 +157,126 @@ a {
|
||||
|
||||
.button:disabled:hover {
|
||||
background-color: var(--blue800);
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.button-stepper {
|
||||
cursor: pointer;
|
||||
color: var(--blue600);
|
||||
color: var(--blue500);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
width: 4rem;
|
||||
margin: 0 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
.button-stepper:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-wrapper {
|
||||
color: var(--slate400);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.refresh-wrapper:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-button {
|
||||
cursor: pointer;
|
||||
color: var(--slate300);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
padding-right: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.refresh-button:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-span {
|
||||
width: 1.5em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.refresh-icon {
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.stepper-icon {
|
||||
display: inline-flex;
|
||||
align-self: center;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.left-pad {
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.right-pad {
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
.stepper-icon svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 0.8rem;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--slate500);
|
||||
border-radius: 4px;
|
||||
border-bottom: 1px solid white;
|
||||
padding: 0.8rem 0;
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
.box-text {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin: 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1.5rem;
|
||||
padding: 0 1.5rem;
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
@@ -188,6 +294,57 @@ a {
|
||||
background: var(--slate500);
|
||||
}
|
||||
|
||||
.users-wrapper,
|
||||
.feedback-wrapper {
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.keys-header {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.users-header {
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
font-family: "DM Sans", sans-serif;
|
||||
}
|
||||
|
||||
.join-group-button,
|
||||
.send-feedback-button {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.github-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.github-button {
|
||||
cursor: pointer;
|
||||
color: var(--slate100);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
padding-right: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
overflow: visible !important;
|
||||
fill: currentColor;
|
||||
color: #f0f6fc !important;
|
||||
vertical-align: middle !important;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
@@ -196,7 +353,7 @@ a {
|
||||
border-right: 2px solid transparent;
|
||||
animation: spin 1s linear infinite;
|
||||
z-index: 20;
|
||||
margin-left: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
"use client"
|
||||
import Stepper from "@/components/Stepper"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import { useSemaphoreContext } from "@/context/SemaphoreContext"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useEffect, useMemo } from "react"
|
||||
import Feedback from "../../../contract-artifacts/Feedback.json"
|
||||
import { ethers } from "ethers"
|
||||
import useSemaphoreIdentity from "@/hooks/useSemaphoreIdentity"
|
||||
import { useState } from "react"
|
||||
|
||||
export default function GroupsPage() {
|
||||
const router = useRouter()
|
||||
const { setLog } = useLogContext()
|
||||
const { _users, refreshUsers, addUser } = useSemaphoreContext()
|
||||
const [_loading, setLoading] = useState(false)
|
||||
const { _identity } = useSemaphoreIdentity()
|
||||
|
||||
useEffect(() => {
|
||||
if (_users.length > 0) {
|
||||
setLog(`${_users.length} user${_users.length > 1 ? "s" : ""} retrieved from the group 🤙🏽`)
|
||||
}
|
||||
}, [_users, setLog])
|
||||
|
||||
const users = useMemo(() => [..._users].reverse(), [_users])
|
||||
|
||||
const joinGroup = useCallback(async () => {
|
||||
if (!_identity) {
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
setLog(`Joining the Feedback group...`)
|
||||
|
||||
let joinedGroup: boolean = false
|
||||
|
||||
if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
abi: Feedback.abi,
|
||||
address: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string,
|
||||
functionName: "joinGroup",
|
||||
functionParameters: [_identity.commitment.toString()]
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
joinedGroup = true
|
||||
}
|
||||
} else if (
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT &&
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID &&
|
||||
process.env.GELATO_RELAYER_API_KEY
|
||||
) {
|
||||
const iface = new ethers.Interface(Feedback.abi)
|
||||
const request = {
|
||||
chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID,
|
||||
target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
data: iface.encodeFunctionData("joinGroup", [_identity.commitment.toString()]),
|
||||
sponsorApiKey: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request)
|
||||
})
|
||||
|
||||
if (response.status === 201) {
|
||||
joinedGroup = true
|
||||
}
|
||||
} else {
|
||||
const response = await fetch("api/join", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
identityCommitment: _identity.commitment.toString()
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
joinedGroup = true
|
||||
}
|
||||
}
|
||||
|
||||
if (joinedGroup) {
|
||||
addUser(_identity.commitment.toString())
|
||||
|
||||
setLog(`You have joined the Feedback group event 🎉 Share your feedback anonymously!`)
|
||||
} else {
|
||||
setLog("Some error occurred, please try again!")
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}, [_identity, addUser, setLoading, setLog])
|
||||
|
||||
const userHasJoined = useMemo(
|
||||
() => _identity !== undefined && _users.includes(_identity.commitment.toString()),
|
||||
[_identity, _users]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Groups</h2>
|
||||
|
||||
<p>
|
||||
<a
|
||||
href="https://docs.semaphore.pse.dev/guides/groups"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Semaphore groups
|
||||
</a>{" "}
|
||||
are{" "}
|
||||
<a
|
||||
href="https://zkkit.pse.dev/classes/_zk_kit_imt.LeanIMT.html"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Lean incremental Merkle trees
|
||||
</a>{" "}
|
||||
in which each leaf contains an identity commitment for a user. Groups can be abstracted to represent
|
||||
events, polls, or organizations.
|
||||
</p>
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="text-top">
|
||||
<h3 className="users-header">Group users ({_users.length})</h3>
|
||||
<button className="refresh-button" onClick={refreshUsers}>
|
||||
<span className="refresh-span">
|
||||
<svg viewBox="0 0 24 24" focusable="false" className="refresh-icon">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5.463 4.43301C7.27756 2.86067 9.59899 1.99666 12 2.00001C17.523 2.00001 22 6.47701 22 12C22 14.136 21.33 16.116 20.19 17.74L17 12H20C20.0001 10.4316 19.5392 8.89781 18.6747 7.58927C17.8101 6.28072 16.5799 5.25517 15.1372 4.64013C13.6944 4.0251 12.1027 3.84771 10.56 4.13003C9.0172 4.41234 7.59145 5.14191 6.46 6.22801L5.463 4.43301ZM18.537 19.567C16.7224 21.1393 14.401 22.0034 12 22C6.477 22 2 17.523 2 12C2 9.86401 2.67 7.88401 3.81 6.26001L7 12H4C3.99987 13.5684 4.46075 15.1022 5.32534 16.4108C6.18992 17.7193 7.42007 18.7449 8.86282 19.3599C10.3056 19.9749 11.8973 20.1523 13.44 19.87C14.9828 19.5877 16.4085 18.8581 17.54 17.772L18.537 19.567Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{_users.length > 0 && (
|
||||
<div className="users-wrapper">
|
||||
{users.map((user, i) => (
|
||||
<div key={i}>
|
||||
<p className="box box-text">
|
||||
{_identity?.commitment.toString() === user ? <b>{user}</b> : user}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="join-group-button">
|
||||
<button
|
||||
className="button"
|
||||
onClick={joinGroup}
|
||||
disabled={_loading || !_identity || userHasJoined}
|
||||
type="button"
|
||||
>
|
||||
<span>Join group</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="divider" />
|
||||
|
||||
<Stepper
|
||||
step={2}
|
||||
onPrevClick={() => router.push("/")}
|
||||
onNextClick={userHasJoined ? () => router.push("/proofs") : undefined}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Identity } from "@semaphore-protocol/core"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import Feedback from "../../../contract-artifacts/Feedback.json"
|
||||
import Stepper from "@/components/Stepper"
|
||||
import LogsContext from "@/context/LogsContext"
|
||||
import SemaphoreContext from "@/context/SemaphoreContext"
|
||||
|
||||
export default function GroupsPage() {
|
||||
const router = useRouter()
|
||||
const { setLogs } = useContext(LogsContext)
|
||||
const { _users, refreshUsers, addUser } = useContext(SemaphoreContext)
|
||||
const [_loading, setLoading] = useState(false)
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (!privateKey) {
|
||||
router.push("/")
|
||||
return
|
||||
}
|
||||
|
||||
setIdentity(new Identity(privateKey))
|
||||
}, [router])
|
||||
|
||||
useEffect(() => {
|
||||
if (_users.length > 0) {
|
||||
setLogs(`${_users.length} user${_users.length > 1 ? "s" : ""} retrieved from the group 🤙🏽`)
|
||||
}
|
||||
}, [_users, setLogs])
|
||||
|
||||
const joinGroup = useCallback(async () => {
|
||||
if (!_identity) {
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
setLogs(`Joining the Feedback group...`)
|
||||
|
||||
let response: any
|
||||
|
||||
if (process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
response = await fetch(process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
abi: Feedback.abi,
|
||||
address: process.env.FEEDBACK_CONTRACT_ADDRESS,
|
||||
functionName: "joinGroup",
|
||||
functionParameters: [_identity.commitment.toString()]
|
||||
})
|
||||
})
|
||||
} else {
|
||||
response = await fetch("api/join", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
identityCommitment: _identity.commitment.toString()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
addUser(_identity.commitment.toString())
|
||||
|
||||
setLogs(`You have joined the Feedback group event 🎉 Share your feedback anonymously!`)
|
||||
} else {
|
||||
setLogs("Some error occurred, please try again!")
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}, [_identity, addUser, setLogs])
|
||||
|
||||
const userHasJoined = useCallback((identity: Identity) => _users.includes(identity.commitment.toString()), [_users])
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Groups</h2>
|
||||
|
||||
<p>
|
||||
<a
|
||||
href="https://docs.semaphore.pse.dev/guides/groups"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Semaphore groups
|
||||
</a>{" "}
|
||||
are{" "}
|
||||
<a
|
||||
href="https://zkkit.pse.dev/classes/_zk_kit_imt.LeanIMT.html"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Lean incremental Merkle trees
|
||||
</a>{" "}
|
||||
in which each leaf contains an identity commitment for a user. Groups can be abstracted to represent
|
||||
events, polls, or organizations.
|
||||
</p>
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="text-top">
|
||||
<h3>Group users ({_users.length})</h3>
|
||||
<button className="button-link" onClick={refreshUsers}>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
className="button"
|
||||
onClick={joinGroup}
|
||||
disabled={_loading || !_identity || userHasJoined(_identity)}
|
||||
>
|
||||
<span>Join group</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{_users.length > 0 && (
|
||||
<div>
|
||||
{_users.map((user, i) => (
|
||||
<div key={i}>
|
||||
<p className="box box-text">{user.toString()}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<Stepper
|
||||
step={2}
|
||||
onPrevClick={() => router.push("/")}
|
||||
onNextClick={_identity && userHasJoined(_identity) ? () => router.push("/proofs") : undefined}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import PageContainer from "@/components/PageContainer"
|
||||
import type { Metadata } from "next"
|
||||
import { Inter } from "next/font/google"
|
||||
import { LogContextProvider } from "@/context/LogContext"
|
||||
import { SemaphoreContextProvider } from "@/context/SemaphoreContext"
|
||||
import "./globals.css"
|
||||
|
||||
import { Inter } from "next/font/google"
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -32,8 +34,20 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"></link>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com"></link>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap"
|
||||
rel="stylesheet"
|
||||
></link>
|
||||
</head>
|
||||
<body suppressHydrationWarning className={inter.className}>
|
||||
<PageContainer>{children}</PageContainer>
|
||||
<SemaphoreContextProvider>
|
||||
<LogContextProvider>
|
||||
<PageContainer>{children}</PageContainer>
|
||||
</LogContextProvider>
|
||||
</SemaphoreContextProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
@@ -2,42 +2,42 @@
|
||||
|
||||
import { Identity } from "@semaphore-protocol/core"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import Stepper from "../components/Stepper"
|
||||
import LogsContext from "../context/LogsContext"
|
||||
import { useLogContext } from "../context/LogContext"
|
||||
|
||||
export default function IdentitiesPage() {
|
||||
const router = useRouter()
|
||||
const { setLogs } = useContext(LogsContext)
|
||||
const { setLog } = useLogContext()
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (privateKey) {
|
||||
const identity = new Identity(privateKey)
|
||||
const identity = Identity.import(privateKey)
|
||||
|
||||
setIdentity(identity)
|
||||
|
||||
setLogs("Your Semaphore identity has been retrieved from the browser cache 👌🏽")
|
||||
setLog("Your Semaphore identity has been retrieved from the browser cache 👌🏽")
|
||||
} else {
|
||||
setLogs("Create your Semaphore identity 👆🏽")
|
||||
setLog("Create your Semaphore identity 👆🏽")
|
||||
}
|
||||
}, [setLogs])
|
||||
}, [setLog])
|
||||
|
||||
const createIdentity = useCallback(async () => {
|
||||
const identity = new Identity()
|
||||
|
||||
setIdentity(identity)
|
||||
|
||||
localStorage.setItem("identity", identity.privateKey.toString())
|
||||
localStorage.setItem("identity", identity.export())
|
||||
|
||||
setLogs("Your new Semaphore identity has just been created 🎉")
|
||||
}, [setLogs])
|
||||
setLog("Your new Semaphore identity has just been created 🎉")
|
||||
}, [setLog])
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="font-size: 3rem;">Identities</h2>
|
||||
<h2>Identities</h2>
|
||||
|
||||
<p>
|
||||
The identity of a user in the Semaphore protocol. A{" "}
|
||||
@@ -59,35 +59,36 @@ export default function IdentitiesPage() {
|
||||
public/private key pair and a commitment, used as the public identifier of the identity.
|
||||
</p>
|
||||
|
||||
<div className="divider"></div>
|
||||
<div className="divider" />
|
||||
|
||||
<div className="text-top">
|
||||
<div className="keys-header">
|
||||
<h3>Identity</h3>
|
||||
{_identity && (
|
||||
<button className="button-link" onClick={createIdentity}>
|
||||
New
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{_identity ? (
|
||||
<div>
|
||||
<div className="box">
|
||||
<p className="box-text">Private Key: {_identity.privateKey.toString()}</p>
|
||||
<p className="box-text">Commitment: {_identity.commitment.toString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button className="button" onClick={createIdentity}>
|
||||
Create identity
|
||||
</button>
|
||||
{_identity && (
|
||||
<div className="key-wrapper">
|
||||
<p>
|
||||
<b>Private Key (base64)</b>:<br /> {_identity.export()}
|
||||
</p>
|
||||
<p>
|
||||
<b>Public Key</b>:<br /> [{_identity.publicKey[0].toString()},{" "}
|
||||
{_identity.publicKey[1].toString()}]
|
||||
</p>
|
||||
<p>
|
||||
<b>Commitment</b>:<br /> {_identity.commitment.toString()}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="divider"></div>
|
||||
<div>
|
||||
<button className="button" onClick={createIdentity} type="button">
|
||||
Create identity
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Stepper step={1} onNextClick={_identity && (() => router.push("/groups"))} />
|
||||
<div className="divider" />
|
||||
|
||||
<Stepper step={1} onNextClick={_identity && (() => router.push("/group"))} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import { Group, Identity, generateProof } from "@semaphore-protocol/core"
|
||||
import Stepper from "@/components/Stepper"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import { useSemaphoreContext } from "@/context/SemaphoreContext"
|
||||
import { generateProof, Group } from "@semaphore-protocol/core"
|
||||
import { encodeBytes32String, ethers } from "ethers"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import Feedback from "../../../contract-artifacts/Feedback.json"
|
||||
import Stepper from "../../components/Stepper"
|
||||
import LogsContext from "../../context/LogsContext"
|
||||
import SemaphoreContext from "../../context/SemaphoreContext"
|
||||
import useSemaphoreIdentity from "@/hooks/useSemaphoreIdentity"
|
||||
|
||||
export default function ProofsPage() {
|
||||
const router = useRouter()
|
||||
const { setLogs } = useContext(LogsContext)
|
||||
const { _users, _feedback, refreshFeedback, addFeedback } = useContext(SemaphoreContext)
|
||||
const { setLog } = useLogContext()
|
||||
const { _users, _feedback, refreshFeedback, addFeedback } = useSemaphoreContext()
|
||||
const [_loading, setLoading] = useState(false)
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (!privateKey) {
|
||||
router.push("/")
|
||||
return
|
||||
}
|
||||
|
||||
setIdentity(new Identity(privateKey))
|
||||
}, [router])
|
||||
const { _identity } = useSemaphoreIdentity()
|
||||
|
||||
useEffect(() => {
|
||||
if (_feedback.length > 0) {
|
||||
setLogs(`${_feedback.length} feedback retrieved from the group 🤙🏽`)
|
||||
setLog(`${_feedback.length} feedback retrieved from the group 🤙🏽`)
|
||||
}
|
||||
}, [_feedback, setLogs])
|
||||
}, [_feedback, setLog])
|
||||
|
||||
const feedback = useMemo(() => [..._feedback].reverse(), [_feedback])
|
||||
|
||||
const sendFeedback = useCallback(async () => {
|
||||
if (!_identity) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_GROUP_ID !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_GROUP_ID in your .env file")
|
||||
}
|
||||
|
||||
const feedback = prompt("Please enter your feedback:")
|
||||
|
||||
if (feedback && _users) {
|
||||
setLoading(true)
|
||||
|
||||
setLogs(`Posting your anonymous feedback...`)
|
||||
setLog(`Posting your anonymous feedback...`)
|
||||
|
||||
try {
|
||||
const group = new Group(_users)
|
||||
|
||||
const { points, merkleTreeDepth, merkleTreeRoot, nullifier, message } = await generateProof(
|
||||
const message = encodeBytes32String(feedback)
|
||||
|
||||
const { points, merkleTreeDepth, merkleTreeRoot, nullifier } = await generateProof(
|
||||
_identity,
|
||||
group,
|
||||
feedback,
|
||||
message,
|
||||
process.env.NEXT_PUBLIC_GROUP_ID as string
|
||||
)
|
||||
|
||||
let response: any
|
||||
|
||||
if (process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
response = await fetch(process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
let feedbackSent: boolean = false
|
||||
const params = [merkleTreeDepth, merkleTreeRoot, nullifier, message, points]
|
||||
if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
abi: Feedback.abi,
|
||||
address: process.env.FEEDBACK_CONTRACT_ADDRESS,
|
||||
address: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
functionName: "sendFeedback",
|
||||
functionParameters: [merkleTreeDepth, merkleTreeRoot, nullifier, message, points]
|
||||
functionParameters: params
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
feedbackSent = true
|
||||
}
|
||||
} else if (
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT &&
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID &&
|
||||
process.env.GELATO_RELAYER_API_KEY
|
||||
) {
|
||||
const iface = new ethers.Interface(Feedback.abi)
|
||||
const request = {
|
||||
chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID,
|
||||
target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
data: iface.encodeFunctionData("sendFeedback", params),
|
||||
sponsorApiKey: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request)
|
||||
})
|
||||
|
||||
if (response.status === 201) {
|
||||
feedbackSent = true
|
||||
}
|
||||
} else {
|
||||
response = await fetch("api/feedback", {
|
||||
const response = await fetch("api/feedback", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
@@ -83,24 +99,28 @@ export default function ProofsPage() {
|
||||
points
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
feedbackSent = true
|
||||
}
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
if (feedbackSent) {
|
||||
addFeedback(feedback)
|
||||
|
||||
setLogs(`Your feedback has been posted 🎉`)
|
||||
setLog(`Your feedback has been posted 🎉`)
|
||||
} else {
|
||||
setLogs("Some error occurred, please try again!")
|
||||
setLog("Some error occurred, please try again!")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
setLogs("Some error occurred, please try again!")
|
||||
setLog("Some error occurred, please try again!")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}, [_identity, _users, addFeedback, setLogs])
|
||||
}, [_identity, _users, addFeedback, setLoading, setLog])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -122,22 +142,23 @@ export default function ProofsPage() {
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="text-top">
|
||||
<h3>Feedback messages ({_feedback.length})</h3>
|
||||
<button className="button-link" onClick={refreshFeedback}>
|
||||
<h3>Feedback ({_feedback.length})</h3>
|
||||
<button className="refresh-button" onClick={refreshFeedback}>
|
||||
<span className="refresh-span">
|
||||
<svg viewBox="0 0 24 24" focusable="false" className="refresh-icon">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5.463 4.43301C7.27756 2.86067 9.59899 1.99666 12 2.00001C17.523 2.00001 22 6.47701 22 12C22 14.136 21.33 16.116 20.19 17.74L17 12H20C20.0001 10.4316 19.5392 8.89781 18.6747 7.58927C17.8101 6.28072 16.5799 5.25517 15.1372 4.64013C13.6944 4.0251 12.1027 3.84771 10.56 4.13003C9.0172 4.41234 7.59145 5.14191 6.46 6.22801L5.463 4.43301ZM18.537 19.567C16.7224 21.1393 14.401 22.0034 12 22C6.477 22 2 17.523 2 12C2 9.86401 2.67 7.88401 3.81 6.26001L7 12H4C3.99987 13.5684 4.46075 15.1022 5.32534 16.4108C6.18992 17.7193 7.42007 18.7449 8.86282 19.3599C10.3056 19.9749 11.8973 20.1523 13.44 19.87C14.9828 19.5877 16.4085 18.8581 17.54 17.772L18.537 19.567Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button className="button" onClick={sendFeedback} disabled={_loading}>
|
||||
<span>Send Feedback</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{_feedback.length > 0 && (
|
||||
<div>
|
||||
{_feedback.map((f, i) => (
|
||||
{feedback.length > 0 && (
|
||||
<div className="feedback-wrapper">
|
||||
{feedback.map((f, i) => (
|
||||
<div key={i}>
|
||||
<p className="box box-text">{f}</p>
|
||||
</div>
|
||||
@@ -145,9 +166,16 @@ export default function ProofsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="send-feedback-button">
|
||||
<button className="button" onClick={sendFeedback} disabled={_loading}>
|
||||
<span>Send Feedback</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<Stepper step={3} onPrevClick={() => router.push("/groups")} />
|
||||
<Stepper step={3} onPrevClick={() => router.push("/group")} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import LogsContext from "@/context/LogsContext"
|
||||
import SemaphoreContext from "@/context/SemaphoreContext"
|
||||
import useSemaphore from "@/hooks/useSemaphore"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import shortenString from "@/utils/shortenString"
|
||||
import { SupportedNetwork } from "@semaphore-protocol/utils"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
|
||||
export default function PageContainer({
|
||||
@@ -15,15 +11,9 @@ export default function PageContainer({
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
const pathname = usePathname()
|
||||
const semaphore = useSemaphore()
|
||||
const [_logs, setLogs] = useState<string>("")
|
||||
const { log } = useLogContext()
|
||||
|
||||
useEffect(() => {
|
||||
semaphore.refreshUsers()
|
||||
semaphore.refreshFeedback()
|
||||
}, [])
|
||||
|
||||
function getExplorerLink(network: SupportedNetwork, address: string) {
|
||||
function getExplorerLink(network: string, address: string) {
|
||||
switch (network) {
|
||||
case "sepolia":
|
||||
return `https://sepolia.etherscan.io/address/${address}`
|
||||
@@ -35,7 +25,7 @@ export default function PageContainer({
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<div className="header">
|
||||
<Link href="/" className="header-left">
|
||||
Feedback
|
||||
@@ -43,7 +33,7 @@ export default function PageContainer({
|
||||
<div className="header-right">
|
||||
<a
|
||||
href={getExplorerLink(
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK as SupportedNetwork,
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string,
|
||||
process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
)}
|
||||
target="_blank"
|
||||
@@ -52,47 +42,34 @@ export default function PageContainer({
|
||||
<div>{shortenString(process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string, [6, 4])}</div>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/semaphore-protocol/semaphore"
|
||||
href="https://github.com/semaphore-protocol/semaphore/tree/main/packages/cli-template-monorepo-ethers"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-github"
|
||||
>
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
<button type="button" className="github-button" aria-label="Github repository">
|
||||
<svg
|
||||
height="32"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
width="32"
|
||||
data-view-component="true"
|
||||
>
|
||||
<path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="container">
|
||||
<SemaphoreContext.Provider value={semaphore}>
|
||||
<LogsContext.Provider
|
||||
value={{
|
||||
_logs,
|
||||
setLogs
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LogsContext.Provider>
|
||||
</SemaphoreContext.Provider>
|
||||
</div>
|
||||
<div className="container">{children}</div>
|
||||
|
||||
<div className="divider-footer"></div>
|
||||
<div className="divider-footer" />
|
||||
|
||||
<div className="footer">
|
||||
{_logs.endsWith("...")}
|
||||
<p>{_logs || `Current step: ${pathname}`}</p>
|
||||
{log.endsWith("...")}
|
||||
<p>{log || `Current step: ${pathname}`}</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client"
|
||||
|
||||
export type StepperProps = {
|
||||
step: number
|
||||
onPrevClick?: () => void
|
||||
@@ -8,21 +10,47 @@ export default function Stepper({ step, onPrevClick, onNextClick }: StepperProps
|
||||
return (
|
||||
<div className="stepper">
|
||||
{onPrevClick !== undefined ? (
|
||||
<button className="button-stepper" disabled={!onPrevClick} onClick={onPrevClick || undefined}>
|
||||
<button
|
||||
className="button-stepper"
|
||||
disabled={!onPrevClick}
|
||||
onClick={onPrevClick || undefined}
|
||||
type="button"
|
||||
>
|
||||
<span className="stepper-icon left-pad">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16.2425 6.34317L14.8283 4.92896L7.75732 12L14.8284 19.0711L16.2426 17.6569L10.5857 12L16.2425 6.34317Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Prev
|
||||
</button>
|
||||
) : (
|
||||
<span></span>
|
||||
<button className="button-stepper"></button>
|
||||
)}
|
||||
|
||||
<p>{step.toString()}/3</p>
|
||||
|
||||
{onNextClick !== undefined ? (
|
||||
<button className="button-stepper" disabled={!onNextClick} onClick={onNextClick || undefined}>
|
||||
<button
|
||||
className="button-stepper"
|
||||
disabled={!onNextClick}
|
||||
onClick={onNextClick || undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
<span className="stepper-icon right-pad">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M10.5859 6.34317L12.0001 4.92896L19.0712 12L12.0001 19.0711L10.5859 17.6569L16.2428 12L10.5859 6.34317Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<span></span>
|
||||
<span className="button-stepper" />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"use client"
|
||||
|
||||
import React, { createContext, ReactNode, useContext, useState } from "react"
|
||||
|
||||
export type LogContextType = {
|
||||
log: string
|
||||
setLog: (logs: string) => void
|
||||
}
|
||||
|
||||
const LogContext = createContext<LogContextType | null>(null)
|
||||
|
||||
interface ProviderProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const LogContextProvider: React.FC<ProviderProps> = ({ children }) => {
|
||||
const [log, setLog] = useState<string>("")
|
||||
|
||||
return (
|
||||
<LogContext.Provider
|
||||
value={{
|
||||
log,
|
||||
setLog
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LogContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useLogContext = () => {
|
||||
const context = useContext(LogContext)
|
||||
if (context === null) {
|
||||
throw new Error("LogContext must be used within a LogContextProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from "react"
|
||||
|
||||
export type LogsContextType = {
|
||||
_logs: string
|
||||
setLogs: (logs: string) => void
|
||||
}
|
||||
|
||||
export default React.createContext<LogsContextType>({
|
||||
_logs: "",
|
||||
setLogs: (logs: string) => logs
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from "react"
|
||||
|
||||
export type SemaphoreContextType = {
|
||||
_users: string[]
|
||||
_feedback: string[]
|
||||
refreshUsers: () => Promise<void>
|
||||
addUser: (user: string) => void
|
||||
refreshFeedback: () => Promise<void>
|
||||
addFeedback: (feedback: string) => void
|
||||
}
|
||||
|
||||
export default React.createContext<SemaphoreContextType>({
|
||||
_users: [],
|
||||
_feedback: [],
|
||||
refreshUsers: () => Promise.resolve(),
|
||||
addUser: () => {},
|
||||
refreshFeedback: () => Promise.resolve(),
|
||||
addFeedback: () => {}
|
||||
})
|
||||
@@ -0,0 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import React, { createContext, ReactNode, useCallback, useContext, useEffect, useState } from "react"
|
||||
import { SemaphoreEthers } from "@semaphore-protocol/data"
|
||||
import { decodeBytes32String, toBeHex } from "ethers"
|
||||
|
||||
export type SemaphoreContextType = {
|
||||
_users: string[]
|
||||
_feedback: string[]
|
||||
refreshUsers: () => Promise<void>
|
||||
addUser: (user: string) => void
|
||||
refreshFeedback: () => Promise<void>
|
||||
addFeedback: (feedback: string) => void
|
||||
}
|
||||
|
||||
const SemaphoreContext = createContext<SemaphoreContextType | null>(null)
|
||||
|
||||
interface ProviderProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const ethereumNetwork =
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK === "localhost"
|
||||
? "http://127.0.0.1:8545"
|
||||
: process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
|
||||
export const SemaphoreContextProvider: React.FC<ProviderProps> = ({ children }) => {
|
||||
const [_users, setUsers] = useState<any[]>([])
|
||||
const [_feedback, setFeedback] = useState<string[]>([])
|
||||
|
||||
const refreshUsers = useCallback(async (): Promise<void> => {
|
||||
const semaphore = new SemaphoreEthers(ethereumNetwork, {
|
||||
address: process.env.NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS,
|
||||
projectId: process.env.NEXT_PUBLIC_INFURA_API_KEY
|
||||
})
|
||||
|
||||
const members = await semaphore.getGroupMembers(process.env.NEXT_PUBLIC_GROUP_ID as string)
|
||||
|
||||
setUsers(members.map((member) => member.toString()))
|
||||
}, [])
|
||||
|
||||
const addUser = useCallback(
|
||||
(user: any) => {
|
||||
setUsers([..._users, user])
|
||||
},
|
||||
[_users]
|
||||
)
|
||||
|
||||
const refreshFeedback = useCallback(async (): Promise<void> => {
|
||||
const semaphore = new SemaphoreEthers(ethereumNetwork, {
|
||||
address: process.env.NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS,
|
||||
projectId: process.env.NEXT_PUBLIC_INFURA_API_KEY
|
||||
})
|
||||
|
||||
const proofs = await semaphore.getGroupValidatedProofs(process.env.NEXT_PUBLIC_GROUP_ID as string)
|
||||
|
||||
setFeedback(proofs.map(({ message }: any) => decodeBytes32String(toBeHex(message, 32))))
|
||||
}, [])
|
||||
|
||||
const addFeedback = useCallback(
|
||||
(feedback: string) => {
|
||||
setFeedback([..._feedback, feedback])
|
||||
},
|
||||
[_feedback]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
refreshUsers()
|
||||
refreshFeedback()
|
||||
}, [refreshFeedback, refreshUsers])
|
||||
|
||||
return (
|
||||
<SemaphoreContext.Provider
|
||||
value={{
|
||||
_users,
|
||||
_feedback,
|
||||
refreshUsers,
|
||||
addUser,
|
||||
refreshFeedback,
|
||||
addFeedback
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SemaphoreContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useSemaphoreContext = () => {
|
||||
const context = useContext(SemaphoreContext)
|
||||
if (context === null) {
|
||||
throw new Error("SemaphoreContext must be used within a SemaphoreContextProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { SemaphoreEthers } from "@semaphore-protocol/data"
|
||||
import { decodeBytes32String, toBeHex } from "ethers"
|
||||
import { useCallback, useState } from "react"
|
||||
import { SemaphoreContextType } from "../context/SemaphoreContext"
|
||||
|
||||
const ethereumNetwork =
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK === "localhost"
|
||||
? "http://127.0.0.1:8545"
|
||||
: process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
|
||||
export default function useSemaphore(): SemaphoreContextType {
|
||||
const [_users, setUsers] = useState<string[]>([])
|
||||
const [_feedback, setFeedback] = useState<string[]>([])
|
||||
|
||||
const refreshUsers = useCallback(async (): Promise<void> => {
|
||||
const semaphore = new SemaphoreEthers(ethereumNetwork, {
|
||||
address: process.env.NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS
|
||||
})
|
||||
|
||||
const members = await semaphore.getGroupMembers(process.env.NEXT_PUBLIC_GROUP_ID as string)
|
||||
|
||||
setUsers(members)
|
||||
}, [])
|
||||
|
||||
const addUser = useCallback(
|
||||
(user: any) => {
|
||||
setUsers([..._users, user])
|
||||
},
|
||||
[_users]
|
||||
)
|
||||
|
||||
const refreshFeedback = useCallback(async (): Promise<void> => {
|
||||
const semaphore = new SemaphoreEthers(ethereumNetwork, {
|
||||
address: process.env.NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS
|
||||
})
|
||||
|
||||
const proofs = await semaphore.getGroupValidatedProofs(process.env.NEXT_PUBLIC_GROUP_ID as string)
|
||||
|
||||
setFeedback(proofs.map(({ message }: any) => decodeBytes32String(toBeHex(message, 32))))
|
||||
}, [])
|
||||
|
||||
const addFeedback = useCallback(
|
||||
(feedback: string) => {
|
||||
setFeedback([..._feedback, feedback])
|
||||
},
|
||||
[_feedback]
|
||||
)
|
||||
|
||||
return {
|
||||
_users,
|
||||
_feedback,
|
||||
refreshUsers,
|
||||
addUser,
|
||||
refreshFeedback,
|
||||
addFeedback
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { Identity } from "@semaphore-protocol/core"
|
||||
import { useRouter } from "next/navigation"
|
||||
|
||||
export default function useSemaphoreIdentity() {
|
||||
const router = useRouter()
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (!privateKey) {
|
||||
router.push("/")
|
||||
return
|
||||
}
|
||||
|
||||
setIdentity(new Identity(privateKey))
|
||||
}, [router])
|
||||
|
||||
return {
|
||||
_identity
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@semaphore-protocol/cli-template-monorepo-ethers",
|
||||
"version": "4.0.0",
|
||||
"version": "4.4.2",
|
||||
"description": "Semaphore Hardhat + Next.js + SemaphoreEthers template.",
|
||||
"license": "Unlicense",
|
||||
"files": [
|
||||
|
||||
@@ -20,9 +20,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",
|
||||
"@semaphore-protocol/hardhat": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/core": "4.4.2",
|
||||
"@semaphore-protocol/hardhat": "4.4.2",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"@typechain/ethers-v6": "^0.5.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"@types/chai": "^4.2.0",
|
||||
@@ -50,7 +50,7 @@
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/contracts": "4.0.0"
|
||||
"@semaphore-protocol/contracts": "4.4.2"
|
||||
},
|
||||
"packageManager": "yarn@4.1.0"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
NEXT_PUBLIC_DEFAULT_NETWORK=localhost
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9
|
||||
NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
|
||||
NEXT_PUBLIC_GROUP_ID=0
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
NEXT_PUBLIC_DEFAULT_NETWORK=sepolia
|
||||
NEXT_PUBLIC_INFURA_API_KEY=abf67af1010b4b8d877e04244f1eac3d
|
||||
NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS=
|
||||
NEXT_PUBLIC_SEMAPHORE_CONTRACT_ADDRESS=0x1e0d7FF1610e480fC93BdEC510811ea2Ba6d7c2f
|
||||
NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK=https://api.defender.openzeppelin.com/actions/20fce2ae-844b-4ec0-a6a2-90a3350a9d2c/runs/webhook/303216d1-fa7d-4fca-8c5b-7ba1ba544fc7/2T7i9xrkZA5j37hoaQLUuw
|
||||
NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT=https://api.gelato.digital/relays/v2/sponsored-call
|
||||
NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID=11155111
|
||||
NEXT_PUBLIC_GROUP_ID=
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
@@ -7,3 +10,18 @@
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# Auto Generated PWA files
|
||||
public/sw.js
|
||||
public/workbox-*.js
|
||||
public/worker-*.js
|
||||
public/sw.js.map
|
||||
public/workbox-*.js.map
|
||||
public/worker-*.js.map
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
"internalType": "address",
|
||||
"name": "semaphoreAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_groupId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
@@ -92,8 +87,8 @@
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"bytecode": "0x608060405234801561001057600080fd5b5060405161083f38038061083f833981810160405281019061003291906101a8565b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060018190555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c96e71fb600154306040518363ffffffff1660e01b81526004016100d6929190610206565b600060405180830381600087803b1580156100f057600080fd5b505af1158015610104573d6000803e3d6000fd5b50505050505061022f565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061013f82610114565b9050919050565b61014f81610134565b811461015a57600080fd5b50565b60008151905061016c81610146565b92915050565b6000819050919050565b61018581610172565b811461019057600080fd5b50565b6000815190506101a28161017c565b92915050565b600080604083850312156101bf576101be61010f565b5b60006101cd8582860161015d565b92505060206101de85828601610193565b9150509250929050565b6101f181610172565b82525050565b61020081610134565b82525050565b600060408201905061021b60008301856101e8565b61022860208301846101f7565b9392505050565b6106018061023e6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea2646970667358221220f33606b2d5ad7c0dfc5d22afb43476e1974ea7fd160e1f28203a3e433f29cb4964736f6c63430008170033",
|
||||
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea2646970667358221220f33606b2d5ad7c0dfc5d22afb43476e1974ea7fd160e1f28203a3e433f29cb4964736f6c63430008170033",
|
||||
"bytecode": "0x608060405234801561001057600080fd5b506040516108473803806108478339818101604052810190610032919061017d565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635c3f3b60306040518263ffffffff1660e01b81526004016100cb91906101b9565b6020604051808303816000875af11580156100ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010e919061020a565b60018190555050610237565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061014a8261011f565b9050919050565b61015a8161013f565b811461016557600080fd5b50565b60008151905061017781610151565b92915050565b6000602082840312156101935761019261011a565b5b60006101a184828501610168565b91505092915050565b6101b38161013f565b82525050565b60006020820190506101ce60008301846101aa565b92915050565b6000819050919050565b6101e7816101d4565b81146101f257600080fd5b50565b600081519050610204816101de565b92915050565b6000602082840312156102205761021f61011a565b5b600061022e848285016101f5565b91505092915050565b610601806102466000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea264697066735822122078569abd7f309f3107c4d19e9b4a4f4812522ccc5dc57c7ccbe2b06a5ba461b064736f6c63430008170033",
|
||||
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80637b5d2534146100515780637b85d27a1461006f578063a0f44c921461008b578063eed02e4b146100a9575b600080fd5b6100596100c5565b6040516100669190610301565b60405180910390f35b6100896004803603810190610084919061037e565b6100e9565b005b6100936101ea565b6040516100a09190610409565b60405180910390f35b6100c360048036038101906100be9190610424565b6101f0565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040518060c001604052808781526020018681526020018581526020018481526020016001548152602001836008806020026040519081016040528092919082600860200280828437600081840152601f19601f820116905080830192505050505050815250905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0d898dd600154836040518363ffffffff1660e01b81526004016101b0929190610578565b600060405180830381600087803b1580156101ca57600080fd5b505af11580156101de573d6000803e3d6000fd5b50505050505050505050565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631783efc3600154836040518363ffffffff1660e01b815260040161024d9291906105a2565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006102c76102c26102bd84610282565b6102a2565b610282565b9050919050565b60006102d9826102ac565b9050919050565b60006102eb826102ce565b9050919050565b6102fb816102e0565b82525050565b600060208201905061031660008301846102f2565b92915050565b600080fd5b6000819050919050565b61033481610321565b811461033f57600080fd5b50565b6000813590506103518161032b565b92915050565b600080fd5b60008190508260206008028201111561037857610377610357565b5b92915050565b6000806000806000610180868803121561039b5761039a61031c565b5b60006103a988828901610342565b95505060206103ba88828901610342565b94505060406103cb88828901610342565b93505060606103dc88828901610342565b92505060806103ed8882890161035c565b9150509295509295909350565b61040381610321565b82525050565b600060208201905061041e60008301846103fa565b92915050565b60006020828403121561043a5761043961031c565b5b600061044884828501610342565b91505092915050565b61045a81610321565b82525050565b600060089050919050565b600081905092915050565b6000819050919050565b600061048c8383610451565b60208301905092915050565b6000602082019050919050565b6104ae81610460565b6104b8818461046b565b92506104c382610476565b8060005b838110156104f45781516104db8782610480565b96506104e683610498565b9250506001810190506104c7565b505050505050565b6101a0820160008201516105136000850182610451565b5060208201516105266020850182610451565b5060408201516105396040850182610451565b50606082015161054c6060850182610451565b50608082015161055f6080850182610451565b5060a082015161057260a08501826104a5565b50505050565b60006101c08201905061058e60008301856103fa565b61059b60208301846104fc565b9392505050565b60006040820190506105b760008301856103fa565b6105c460208301846103fa565b939250505056fea264697066735822122078569abd7f309f3107c4d19e9b4a4f4812522ccc5dc57c7ccbe2b06a5ba461b064736f6c63430008170033",
|
||||
"linkReferences": {},
|
||||
"deployedLinkReferences": {}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ const nextConfig = withPWA({
|
||||
})({
|
||||
env: {
|
||||
INFURA_API_KEY: process.env.INFURA_API_KEY,
|
||||
ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY
|
||||
ETHEREUM_PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY,
|
||||
GELATO_RELAYER_API_KEY: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@semaphore-protocol/core": "4.0.0",
|
||||
"@semaphore-protocol/data": "4.0.0",
|
||||
"@semaphore-protocol/utils": "4.0.0",
|
||||
"@semaphore-protocol/core": "4.4.2",
|
||||
"@semaphore-protocol/data": "4.4.2",
|
||||
"@semaphore-protocol/utils": "4.4.2",
|
||||
"ethers": "^6.11.1",
|
||||
"next": "14.1.0",
|
||||
"next-pwa": "^5.6.0",
|
||||
|
||||
@@ -3,26 +3,14 @@ import { NextRequest } from "next/server"
|
||||
import Feedback from "../../../../contract-artifacts/Feedback.json"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (typeof process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_DEFAULT_NETWORK in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.INFURA_API_KEY !== "string" && process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "localhost") {
|
||||
throw new Error("Please, define INFURA_API_KEY in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.ETHEREUM_PRIVATE_KEY !== "string") {
|
||||
throw new Error("Please, define ETHEREUM_PRIVATE_KEY in your .env file")
|
||||
}
|
||||
|
||||
const ethereumPrivateKey = process.env.ETHEREUM_PRIVATE_KEY
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
const infuraApiKey = process.env.INFURA_API_KEY
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string
|
||||
const infuraApiKey = process.env.NEXT_PUBLIC_INFURA_API_KEY as string
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
|
||||
const provider =
|
||||
ethereumNetwork === "localhost"
|
||||
|
||||
@@ -3,26 +3,14 @@ import { NextRequest } from "next/server"
|
||||
import Feedback from "../../../../contract-artifacts/Feedback.json"
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
if (typeof process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_DEFAULT_NETWORK in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.INFURA_API_KEY !== "string" && process.env.NEXT_PUBLIC_DEFAULT_NETWORK !== "localhost") {
|
||||
throw new Error("Please, define INFURA_API_KEY in your .env file")
|
||||
}
|
||||
|
||||
if (typeof process.env.ETHEREUM_PRIVATE_KEY !== "string") {
|
||||
throw new Error("Please, define ETHEREUM_PRIVATE_KEY in your .env file")
|
||||
}
|
||||
|
||||
const ethereumPrivateKey = process.env.ETHEREUM_PRIVATE_KEY
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK
|
||||
const infuraApiKey = process.env.INFURA_API_KEY
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS
|
||||
const ethereumNetwork = process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string
|
||||
const infuraApiKey = process.env.NEXT_PUBLIC_INFURA_API_KEY as string
|
||||
const contractAddress = process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
|
||||
const provider =
|
||||
ethereumNetwork === "localhost"
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
:root {
|
||||
--slate100: #f1f5f9;
|
||||
--slate200: #e2e8f0;
|
||||
--slate300: #cbd5e1;
|
||||
--slate400: #94a3b8;
|
||||
--slate500: #64748b;
|
||||
--slate700: #334155;
|
||||
--blue200: #bfdbfe;
|
||||
--blue500: #3b82f6;
|
||||
--blue600: #2563eb;
|
||||
--blue700: #1d4ed8;
|
||||
--blue800: #1e40af;
|
||||
--blue900: #1e3a8a;
|
||||
--blue100: #dde6fc;
|
||||
--blue200: #c3d4fa;
|
||||
--blue300: #9abaf6;
|
||||
--blue400: #6a95f0;
|
||||
--blue500: #4771ea;
|
||||
--blue600: #3555df;
|
||||
--blue700: #2940cc;
|
||||
--blue800: #2735a6;
|
||||
--blue900: #253183;
|
||||
--blue950: #1b2050;
|
||||
--darkBlueBg: #00020d;
|
||||
--slate50: #f7f7f8;
|
||||
--slate100: #eeeef0;
|
||||
--slate200: #d9d9de;
|
||||
--slate300: #b8b9c1;
|
||||
--slate400: #92939e;
|
||||
--slate500: #747583;
|
||||
--slate600: #5e5f6b;
|
||||
--slate700: #4d4e57;
|
||||
--slate800: #42424a;
|
||||
--slate900: #3a3a40;
|
||||
--slate950: #26262b;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: "Outfit", sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -33,17 +44,30 @@ body {
|
||||
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
font-weight: 300;
|
||||
overflow-wrap: break-word;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
b {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.key-wrapper {
|
||||
padding-bottom: 1.5rem;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
max-width: 32rem;
|
||||
|
||||
max-width: 40vw;
|
||||
min-width: 35rem;
|
||||
margin: auto;
|
||||
padding: 1rem;
|
||||
|
||||
height: calc(100vh - 7rem - 1px);
|
||||
padding-bottom: 5rem;
|
||||
min-height: calc(100vh - 3.5rem);
|
||||
}
|
||||
|
||||
@@ -57,28 +81,25 @@ p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.125rem;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
background: var(--slate500);
|
||||
opacity: 0.6;
|
||||
border: 0;
|
||||
border-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
width: 100%;
|
||||
border-color: var(--slate400);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
@@ -89,31 +110,44 @@ h3 {
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--blue500);
|
||||
color: var(--blue400);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--blue400);
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--blue800);
|
||||
width: 100%;
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px;
|
||||
border-radius: 100px;
|
||||
cursor: pointer;
|
||||
color: var(--slate100);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
transition: all 200ms linear;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
opacity: 0.9;
|
||||
font-weight: 400;
|
||||
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
|
||||
transition-duration: 200ms;
|
||||
padding-left: 18px !important;
|
||||
padding-right: 18px !important;
|
||||
height: 2.5rem;
|
||||
min-width: 2.5rem;
|
||||
font-size: 1rem;
|
||||
-webkit-padding-start: 1rem;
|
||||
padding-inline-start: 1rem;
|
||||
-webkit-padding-end: 1rem;
|
||||
padding-inline-end: 1rem;
|
||||
background: var(--blue500);
|
||||
color: white;
|
||||
background-image: linear-gradient(to right, var(--blue500), var(--blue800));
|
||||
transition-timing-function: linear;
|
||||
width: 100%;
|
||||
border: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 3rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: var(--blue900);
|
||||
background-color: var(--blue800);
|
||||
background-image: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
@@ -123,54 +157,126 @@ a {
|
||||
|
||||
.button:disabled:hover {
|
||||
background-color: var(--blue800);
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.button-stepper {
|
||||
cursor: pointer;
|
||||
color: var(--blue600);
|
||||
color: var(--blue500);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
width: 4rem;
|
||||
margin: 0 1rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
.button-stepper:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-wrapper {
|
||||
color: var(--slate400);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.refresh-wrapper:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-button {
|
||||
cursor: pointer;
|
||||
color: var(--slate300);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
padding-right: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.refresh-button:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.refresh-span {
|
||||
width: 1.5em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.refresh-icon {
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.stepper-icon {
|
||||
display: inline-flex;
|
||||
align-self: center;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.left-pad {
|
||||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.right-pad {
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
.stepper-icon svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 0.8rem;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: var(--slate500);
|
||||
border-radius: 4px;
|
||||
border-bottom: 1px solid white;
|
||||
padding: 0.8rem 0;
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
.box-text {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin: 0.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 1.5rem;
|
||||
padding: 0 1.5rem;
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
text-decoration: none !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
@@ -188,6 +294,57 @@ a {
|
||||
background: var(--slate500);
|
||||
}
|
||||
|
||||
.users-wrapper,
|
||||
.feedback-wrapper {
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.keys-header {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.users-header {
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
font-family: "DM Sans", sans-serif;
|
||||
}
|
||||
|
||||
.join-group-button,
|
||||
.send-feedback-button {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.github-icon {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
display: inline-block;
|
||||
line-height: 1em;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.github-button {
|
||||
cursor: pointer;
|
||||
color: var(--slate100);
|
||||
font-size: 1.1rem;
|
||||
border: none;
|
||||
background: none;
|
||||
padding-right: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
overflow: visible !important;
|
||||
fill: currentColor;
|
||||
color: #f0f6fc !important;
|
||||
vertical-align: middle !important;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
@@ -196,7 +353,7 @@ a {
|
||||
border-right: 2px solid transparent;
|
||||
animation: spin 1s linear infinite;
|
||||
z-index: 20;
|
||||
margin-left: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
"use client"
|
||||
import Stepper from "@/components/Stepper"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import { useSemaphoreContext } from "@/context/SemaphoreContext"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useEffect, useMemo } from "react"
|
||||
import Feedback from "../../../contract-artifacts/Feedback.json"
|
||||
import { ethers } from "ethers"
|
||||
import useSemaphoreIdentity from "@/hooks/useSemaphoreIdentity"
|
||||
import { useState } from "react"
|
||||
|
||||
export default function GroupsPage() {
|
||||
const router = useRouter()
|
||||
const { setLog } = useLogContext()
|
||||
const { _users, refreshUsers, addUser } = useSemaphoreContext()
|
||||
const [_loading, setLoading] = useState(false)
|
||||
const { _identity } = useSemaphoreIdentity()
|
||||
|
||||
useEffect(() => {
|
||||
if (_users.length > 0) {
|
||||
setLog(`${_users.length} user${_users.length > 1 ? "s" : ""} retrieved from the group 🤙🏽`)
|
||||
}
|
||||
}, [_users, setLog])
|
||||
|
||||
const users = useMemo(() => [..._users].reverse(), [_users])
|
||||
|
||||
const joinGroup = useCallback(async () => {
|
||||
if (!_identity) {
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
setLog(`Joining the Feedback group...`)
|
||||
|
||||
let joinedGroup: boolean = false
|
||||
|
||||
if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
abi: Feedback.abi,
|
||||
address: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string,
|
||||
functionName: "joinGroup",
|
||||
functionParameters: [_identity.commitment.toString()]
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
joinedGroup = true
|
||||
}
|
||||
} else if (
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT &&
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID &&
|
||||
process.env.GELATO_RELAYER_API_KEY
|
||||
) {
|
||||
const iface = new ethers.Interface(Feedback.abi)
|
||||
const request = {
|
||||
chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID,
|
||||
target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
data: iface.encodeFunctionData("joinGroup", [_identity.commitment.toString()]),
|
||||
sponsorApiKey: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request)
|
||||
})
|
||||
|
||||
if (response.status === 201) {
|
||||
joinedGroup = true
|
||||
}
|
||||
} else {
|
||||
const response = await fetch("api/join", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
identityCommitment: _identity.commitment.toString()
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
joinedGroup = true
|
||||
}
|
||||
}
|
||||
|
||||
if (joinedGroup) {
|
||||
addUser(_identity.commitment.toString())
|
||||
|
||||
setLog(`You have joined the Feedback group event 🎉 Share your feedback anonymously!`)
|
||||
} else {
|
||||
setLog("Some error occurred, please try again!")
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}, [_identity, addUser, setLoading, setLog])
|
||||
|
||||
const userHasJoined = useMemo(
|
||||
() => _identity !== undefined && _users.includes(_identity.commitment.toString()),
|
||||
[_identity, _users]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Groups</h2>
|
||||
|
||||
<p>
|
||||
<a
|
||||
href="https://docs.semaphore.pse.dev/guides/groups"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Semaphore groups
|
||||
</a>{" "}
|
||||
are{" "}
|
||||
<a
|
||||
href="https://zkkit.pse.dev/classes/_zk_kit_imt.LeanIMT.html"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
Lean incremental Merkle trees
|
||||
</a>{" "}
|
||||
in which each leaf contains an identity commitment for a user. Groups can be abstracted to represent
|
||||
events, polls, or organizations.
|
||||
</p>
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="text-top">
|
||||
<h3 className="users-header">Group users ({_users.length})</h3>
|
||||
<button className="refresh-button" onClick={refreshUsers}>
|
||||
<span className="refresh-span">
|
||||
<svg viewBox="0 0 24 24" focusable="false" className="refresh-icon">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5.463 4.43301C7.27756 2.86067 9.59899 1.99666 12 2.00001C17.523 2.00001 22 6.47701 22 12C22 14.136 21.33 16.116 20.19 17.74L17 12H20C20.0001 10.4316 19.5392 8.89781 18.6747 7.58927C17.8101 6.28072 16.5799 5.25517 15.1372 4.64013C13.6944 4.0251 12.1027 3.84771 10.56 4.13003C9.0172 4.41234 7.59145 5.14191 6.46 6.22801L5.463 4.43301ZM18.537 19.567C16.7224 21.1393 14.401 22.0034 12 22C6.477 22 2 17.523 2 12C2 9.86401 2.67 7.88401 3.81 6.26001L7 12H4C3.99987 13.5684 4.46075 15.1022 5.32534 16.4108C6.18992 17.7193 7.42007 18.7449 8.86282 19.3599C10.3056 19.9749 11.8973 20.1523 13.44 19.87C14.9828 19.5877 16.4085 18.8581 17.54 17.772L18.537 19.567Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{_users.length > 0 && (
|
||||
<div className="users-wrapper">
|
||||
{users.map((user, i) => (
|
||||
<div key={i}>
|
||||
<p className="box box-text">
|
||||
{_identity?.commitment.toString() === user ? <b>{user}</b> : user}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="join-group-button">
|
||||
<button
|
||||
className="button"
|
||||
onClick={joinGroup}
|
||||
disabled={_loading || !_identity || userHasJoined}
|
||||
type="button"
|
||||
>
|
||||
<span>Join group</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="divider" />
|
||||
|
||||
<Stepper
|
||||
step={2}
|
||||
onPrevClick={() => router.push("/")}
|
||||
onNextClick={userHasJoined ? () => router.push("/proofs") : undefined}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import PageContainer from "@/components/PageContainer"
|
||||
import type { Metadata } from "next"
|
||||
import { Inter } from "next/font/google"
|
||||
import { LogContextProvider } from "@/context/LogContext"
|
||||
import { SemaphoreContextProvider } from "@/context/SemaphoreContext"
|
||||
import "./globals.css"
|
||||
|
||||
import { Inter } from "next/font/google"
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -32,8 +34,20 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com"></link>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com"></link>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap"
|
||||
rel="stylesheet"
|
||||
></link>
|
||||
</head>
|
||||
<body suppressHydrationWarning className={inter.className}>
|
||||
<PageContainer>{children}</PageContainer>
|
||||
<SemaphoreContextProvider>
|
||||
<LogContextProvider>
|
||||
<PageContainer>{children}</PageContainer>
|
||||
</LogContextProvider>
|
||||
</SemaphoreContextProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
@@ -2,42 +2,42 @@
|
||||
|
||||
import { Identity } from "@semaphore-protocol/core"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import Stepper from "../components/Stepper"
|
||||
import LogsContext from "../context/LogsContext"
|
||||
import { useLogContext } from "../context/LogContext"
|
||||
|
||||
export default function IdentitiesPage() {
|
||||
const router = useRouter()
|
||||
const { setLogs } = useContext(LogsContext)
|
||||
const { setLog } = useLogContext()
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (privateKey) {
|
||||
const identity = new Identity(privateKey)
|
||||
const identity = Identity.import(privateKey)
|
||||
|
||||
setIdentity(identity)
|
||||
|
||||
setLogs("Your Semaphore identity has been retrieved from the browser cache 👌🏽")
|
||||
setLog("Your Semaphore identity has been retrieved from the browser cache 👌🏽")
|
||||
} else {
|
||||
setLogs("Create your Semaphore identity 👆🏽")
|
||||
setLog("Create your Semaphore identity 👆🏽")
|
||||
}
|
||||
}, [setLogs])
|
||||
}, [setLog])
|
||||
|
||||
const createIdentity = useCallback(async () => {
|
||||
const identity = new Identity()
|
||||
|
||||
setIdentity(identity)
|
||||
|
||||
localStorage.setItem("identity", identity.privateKey.toString())
|
||||
localStorage.setItem("identity", identity.export())
|
||||
|
||||
setLogs("Your new Semaphore identity has just been created 🎉")
|
||||
}, [setLogs])
|
||||
setLog("Your new Semaphore identity has just been created 🎉")
|
||||
}, [setLog])
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2 className="font-size: 3rem;">Identities</h2>
|
||||
<h2>Identities</h2>
|
||||
|
||||
<p>
|
||||
The identity of a user in the Semaphore protocol. A{" "}
|
||||
@@ -59,35 +59,36 @@ export default function IdentitiesPage() {
|
||||
public/private key pair and a commitment, used as the public identifier of the identity.
|
||||
</p>
|
||||
|
||||
<div className="divider"></div>
|
||||
<div className="divider" />
|
||||
|
||||
<div className="text-top">
|
||||
<div className="keys-header">
|
||||
<h3>Identity</h3>
|
||||
{_identity && (
|
||||
<button className="button-link" onClick={createIdentity}>
|
||||
New
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{_identity ? (
|
||||
<div>
|
||||
<div className="box">
|
||||
<p className="box-text">Private Key: {_identity.privateKey.toString()}</p>
|
||||
<p className="box-text">Commitment: {_identity.commitment.toString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button className="button" onClick={createIdentity}>
|
||||
Create identity
|
||||
</button>
|
||||
{_identity && (
|
||||
<div className="key-wrapper">
|
||||
<p>
|
||||
<b>Private Key (base64)</b>:<br /> {_identity.export()}
|
||||
</p>
|
||||
<p>
|
||||
<b>Public Key</b>:<br /> [{_identity.publicKey[0].toString()},{" "}
|
||||
{_identity.publicKey[1].toString()}]
|
||||
</p>
|
||||
<p>
|
||||
<b>Commitment</b>:<br /> {_identity.commitment.toString()}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="divider"></div>
|
||||
<div>
|
||||
<button className="button" onClick={createIdentity} type="button">
|
||||
Create identity
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Stepper step={1} onNextClick={_identity && (() => router.push("/groups"))} />
|
||||
<div className="divider" />
|
||||
|
||||
<Stepper step={1} onNextClick={_identity && (() => router.push("/group"))} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,78 +1,94 @@
|
||||
"use client"
|
||||
|
||||
import { Group, Identity, generateProof } from "@semaphore-protocol/core"
|
||||
import Stepper from "@/components/Stepper"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import { useSemaphoreContext } from "@/context/SemaphoreContext"
|
||||
import { generateProof, Group } from "@semaphore-protocol/core"
|
||||
import { encodeBytes32String, ethers } from "ethers"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useContext, useEffect, useState } from "react"
|
||||
import { useCallback, useEffect, useMemo, useState } from "react"
|
||||
import Feedback from "../../../contract-artifacts/Feedback.json"
|
||||
import Stepper from "../../components/Stepper"
|
||||
import LogsContext from "../../context/LogsContext"
|
||||
import SemaphoreContext from "../../context/SemaphoreContext"
|
||||
import useSemaphoreIdentity from "@/hooks/useSemaphoreIdentity"
|
||||
|
||||
export default function ProofsPage() {
|
||||
const router = useRouter()
|
||||
const { setLogs } = useContext(LogsContext)
|
||||
const { _users, _feedback, refreshFeedback, addFeedback } = useContext(SemaphoreContext)
|
||||
const { setLog } = useLogContext()
|
||||
const { _users, _feedback, refreshFeedback, addFeedback } = useSemaphoreContext()
|
||||
const [_loading, setLoading] = useState(false)
|
||||
const [_identity, setIdentity] = useState<Identity>()
|
||||
|
||||
useEffect(() => {
|
||||
const privateKey = localStorage.getItem("identity")
|
||||
|
||||
if (!privateKey) {
|
||||
router.push("/")
|
||||
return
|
||||
}
|
||||
|
||||
setIdentity(new Identity(privateKey))
|
||||
}, [router])
|
||||
const { _identity } = useSemaphoreIdentity()
|
||||
|
||||
useEffect(() => {
|
||||
if (_feedback.length > 0) {
|
||||
setLogs(`${_feedback.length} feedback retrieved from the group 🤙🏽`)
|
||||
setLog(`${_feedback.length} feedback retrieved from the group 🤙🏽`)
|
||||
}
|
||||
}, [_feedback, setLogs])
|
||||
}, [_feedback, setLog])
|
||||
|
||||
const feedback = useMemo(() => [..._feedback].reverse(), [_feedback])
|
||||
|
||||
const sendFeedback = useCallback(async () => {
|
||||
if (!_identity) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof process.env.NEXT_PUBLIC_GROUP_ID !== "string") {
|
||||
throw new Error("Please, define NEXT_PUBLIC_GROUP_ID in your .env file")
|
||||
}
|
||||
|
||||
const feedback = prompt("Please enter your feedback:")
|
||||
|
||||
if (feedback && _users) {
|
||||
setLoading(true)
|
||||
|
||||
setLogs(`Posting your anonymous feedback...`)
|
||||
setLog(`Posting your anonymous feedback...`)
|
||||
|
||||
try {
|
||||
const group = new Group(_users)
|
||||
|
||||
const { points, merkleTreeDepth, merkleTreeRoot, nullifier, message } = await generateProof(
|
||||
const message = encodeBytes32String(feedback)
|
||||
|
||||
const { points, merkleTreeDepth, merkleTreeRoot, nullifier } = await generateProof(
|
||||
_identity,
|
||||
group,
|
||||
feedback,
|
||||
message,
|
||||
process.env.NEXT_PUBLIC_GROUP_ID as string
|
||||
)
|
||||
|
||||
let response: any
|
||||
|
||||
if (process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
response = await fetch(process.env.OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
let feedbackSent: boolean = false
|
||||
const params = [merkleTreeDepth, merkleTreeRoot, nullifier, message, points]
|
||||
if (process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK) {
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_OPENZEPPELIN_AUTOTASK_WEBHOOK, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
abi: Feedback.abi,
|
||||
address: process.env.FEEDBACK_CONTRACT_ADDRESS,
|
||||
address: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
functionName: "sendFeedback",
|
||||
functionParameters: [merkleTreeDepth, merkleTreeRoot, nullifier, message, points]
|
||||
functionParameters: params
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
feedbackSent = true
|
||||
}
|
||||
} else if (
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT &&
|
||||
process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID &&
|
||||
process.env.GELATO_RELAYER_API_KEY
|
||||
) {
|
||||
const iface = new ethers.Interface(Feedback.abi)
|
||||
const request = {
|
||||
chainId: process.env.NEXT_PUBLIC_GELATO_RELAYER_CHAIN_ID,
|
||||
target: process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS,
|
||||
data: iface.encodeFunctionData("sendFeedback", params),
|
||||
sponsorApiKey: process.env.GELATO_RELAYER_API_KEY
|
||||
}
|
||||
const response = await fetch(process.env.NEXT_PUBLIC_GELATO_RELAYER_ENDPOINT, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(request)
|
||||
})
|
||||
|
||||
if (response.status === 201) {
|
||||
feedbackSent = true
|
||||
}
|
||||
} else {
|
||||
response = await fetch("api/feedback", {
|
||||
const response = await fetch("api/feedback", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
@@ -83,24 +99,28 @@ export default function ProofsPage() {
|
||||
points
|
||||
})
|
||||
})
|
||||
|
||||
if (response.status === 200) {
|
||||
feedbackSent = true
|
||||
}
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
if (feedbackSent) {
|
||||
addFeedback(feedback)
|
||||
|
||||
setLogs(`Your feedback has been posted 🎉`)
|
||||
setLog(`Your feedback has been posted 🎉`)
|
||||
} else {
|
||||
setLogs("Some error occurred, please try again!")
|
||||
setLog("Some error occurred, please try again!")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
setLogs("Some error occurred, please try again!")
|
||||
setLog("Some error occurred, please try again!")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}, [_identity, _users, addFeedback, setLogs])
|
||||
}, [_identity, _users, addFeedback, setLoading, setLog])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -122,22 +142,23 @@ export default function ProofsPage() {
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="text-top">
|
||||
<h3>Feedback messages ({_feedback.length})</h3>
|
||||
<button className="button-link" onClick={refreshFeedback}>
|
||||
<h3>Feedback ({_feedback.length})</h3>
|
||||
<button className="refresh-button" onClick={refreshFeedback}>
|
||||
<span className="refresh-span">
|
||||
<svg viewBox="0 0 24 24" focusable="false" className="refresh-icon">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5.463 4.43301C7.27756 2.86067 9.59899 1.99666 12 2.00001C17.523 2.00001 22 6.47701 22 12C22 14.136 21.33 16.116 20.19 17.74L17 12H20C20.0001 10.4316 19.5392 8.89781 18.6747 7.58927C17.8101 6.28072 16.5799 5.25517 15.1372 4.64013C13.6944 4.0251 12.1027 3.84771 10.56 4.13003C9.0172 4.41234 7.59145 5.14191 6.46 6.22801L5.463 4.43301ZM18.537 19.567C16.7224 21.1393 14.401 22.0034 12 22C6.477 22 2 17.523 2 12C2 9.86401 2.67 7.88401 3.81 6.26001L7 12H4C3.99987 13.5684 4.46075 15.1022 5.32534 16.4108C6.18992 17.7193 7.42007 18.7449 8.86282 19.3599C10.3056 19.9749 11.8973 20.1523 13.44 19.87C14.9828 19.5877 16.4085 18.8581 17.54 17.772L18.537 19.567Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button className="button" onClick={sendFeedback} disabled={_loading}>
|
||||
<span>Send Feedback</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{_feedback.length > 0 && (
|
||||
<div>
|
||||
{_feedback.map((f, i) => (
|
||||
{feedback.length > 0 && (
|
||||
<div className="feedback-wrapper">
|
||||
{feedback.map((f, i) => (
|
||||
<div key={i}>
|
||||
<p className="box box-text">{f}</p>
|
||||
</div>
|
||||
@@ -145,9 +166,16 @@ export default function ProofsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="send-feedback-button">
|
||||
<button className="button" onClick={sendFeedback} disabled={_loading}>
|
||||
<span>Send Feedback</span>
|
||||
{_loading && <div className="loader"></div>}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="divider"></div>
|
||||
|
||||
<Stepper step={3} onPrevClick={() => router.push("/groups")} />
|
||||
<Stepper step={3} onPrevClick={() => router.push("/group")} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
"use client"
|
||||
|
||||
import { CacheProvider } from "@chakra-ui/next-js"
|
||||
import { ChakraProvider } from "@chakra-ui/react"
|
||||
import theme from "../styles/index"
|
||||
|
||||
export default function Providers({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<CacheProvider>
|
||||
<ChakraProvider theme={theme}>{children}</ChakraProvider>
|
||||
</CacheProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,12 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import LogsContext from "@/context/LogsContext"
|
||||
import SemaphoreContext from "@/context/SemaphoreContext"
|
||||
import useSemaphore from "@/hooks/useSemaphore"
|
||||
import { useLogContext } from "@/context/LogContext"
|
||||
import shortenString from "@/utils/shortenString"
|
||||
import { SupportedNetwork } from "@semaphore-protocol/utils"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
|
||||
export default function PageContainer({
|
||||
@@ -15,15 +11,9 @@ export default function PageContainer({
|
||||
children: React.ReactNode
|
||||
}>) {
|
||||
const pathname = usePathname()
|
||||
const semaphore = useSemaphore()
|
||||
const [_logs, setLogs] = useState<string>("")
|
||||
const { log } = useLogContext()
|
||||
|
||||
useEffect(() => {
|
||||
semaphore.refreshUsers()
|
||||
semaphore.refreshFeedback()
|
||||
}, [])
|
||||
|
||||
function getExplorerLink(network: SupportedNetwork, address: string) {
|
||||
function getExplorerLink(network: string, address: string) {
|
||||
switch (network) {
|
||||
case "sepolia":
|
||||
return `https://sepolia.etherscan.io/address/${address}`
|
||||
@@ -35,7 +25,7 @@ export default function PageContainer({
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<div className="header">
|
||||
<Link href="/" className="header-left">
|
||||
Feedback
|
||||
@@ -43,7 +33,7 @@ export default function PageContainer({
|
||||
<div className="header-right">
|
||||
<a
|
||||
href={getExplorerLink(
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK as SupportedNetwork,
|
||||
process.env.NEXT_PUBLIC_DEFAULT_NETWORK as string,
|
||||
process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string
|
||||
)}
|
||||
target="_blank"
|
||||
@@ -52,47 +42,34 @@ export default function PageContainer({
|
||||
<div>{shortenString(process.env.NEXT_PUBLIC_FEEDBACK_CONTRACT_ADDRESS as string, [6, 4])}</div>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/semaphore-protocol/semaphore"
|
||||
href="https://github.com/semaphore-protocol/semaphore/tree/main/packages/cli-template-monorepo-subgraph"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-github"
|
||||
>
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
<button type="button" className="github-button" aria-label="Github repository">
|
||||
<svg
|
||||
height="32"
|
||||
aria-hidden="true"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
width="32"
|
||||
data-view-component="true"
|
||||
>
|
||||
<path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="container">
|
||||
<SemaphoreContext.Provider value={semaphore}>
|
||||
<LogsContext.Provider
|
||||
value={{
|
||||
_logs,
|
||||
setLogs
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LogsContext.Provider>
|
||||
</SemaphoreContext.Provider>
|
||||
</div>
|
||||
<div className="container">{children}</div>
|
||||
|
||||
<div className="divider-footer"></div>
|
||||
<div className="divider-footer" />
|
||||
|
||||
<div className="footer">
|
||||
{_logs.endsWith("...")}
|
||||
<p>{_logs || `Current step: ${pathname}`}</p>
|
||||
{log.endsWith("...")}
|
||||
<p>{log || `Current step: ${pathname}`}</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client"
|
||||
|
||||
export type StepperProps = {
|
||||
step: number
|
||||
onPrevClick?: () => void
|
||||
@@ -8,21 +10,47 @@ export default function Stepper({ step, onPrevClick, onNextClick }: StepperProps
|
||||
return (
|
||||
<div className="stepper">
|
||||
{onPrevClick !== undefined ? (
|
||||
<button className="button-stepper" disabled={!onPrevClick} onClick={onPrevClick || undefined}>
|
||||
<button
|
||||
className="button-stepper"
|
||||
disabled={!onPrevClick}
|
||||
onClick={onPrevClick || undefined}
|
||||
type="button"
|
||||
>
|
||||
<span className="stepper-icon left-pad">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M16.2425 6.34317L14.8283 4.92896L7.75732 12L14.8284 19.0711L16.2426 17.6569L10.5857 12L16.2425 6.34317Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
Prev
|
||||
</button>
|
||||
) : (
|
||||
<span></span>
|
||||
<button className="button-stepper"></button>
|
||||
)}
|
||||
|
||||
<p>{step.toString()}/3</p>
|
||||
|
||||
{onNextClick !== undefined ? (
|
||||
<button className="button-stepper" disabled={!onNextClick} onClick={onNextClick || undefined}>
|
||||
<button
|
||||
className="button-stepper"
|
||||
disabled={!onNextClick}
|
||||
onClick={onNextClick || undefined}
|
||||
type="button"
|
||||
>
|
||||
Next
|
||||
<span className="stepper-icon right-pad">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M10.5859 6.34317L12.0001 4.92896L19.0712 12L12.0001 19.0711L10.5859 17.6569L16.2428 12L10.5859 6.34317Z"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<span></span>
|
||||
<span className="button-stepper" />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"use client"
|
||||
|
||||
import React, { createContext, ReactNode, useContext, useState } from "react"
|
||||
|
||||
export type LogContextType = {
|
||||
log: string
|
||||
setLog: (logs: string) => void
|
||||
}
|
||||
|
||||
const LogContext = createContext<LogContextType | null>(null)
|
||||
|
||||
interface ProviderProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export const LogContextProvider: React.FC<ProviderProps> = ({ children }) => {
|
||||
const [log, setLog] = useState<string>("")
|
||||
|
||||
return (
|
||||
<LogContext.Provider
|
||||
value={{
|
||||
log,
|
||||
setLog
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</LogContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useLogContext = () => {
|
||||
const context = useContext(LogContext)
|
||||
if (context === null) {
|
||||
throw new Error("LogContext must be used within a LogContextProvider")
|
||||
}
|
||||
return context
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user