chore: move to vacp2p/foundry-template

This commit is contained in:
rymnc 2023-12-04 15:14:24 +05:30
parent a3193cec3d
commit 0d03e850dd
No known key found for this signature in database
GPG Key ID: AAA088D5C68ECD34
70 changed files with 1653 additions and 16159 deletions

19
.editorconfig Normal file
View File

@ -0,0 +1,19 @@
# EditorConfig http://EditorConfig.org
# top-most EditorConfig file
root = true
# All files
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.sol]
indent_size = 4
[*.tree]
indent_size = 1

View File

@ -1,4 +1,11 @@
ETHERSCAN_API_KEY=<YOUR_ETHERSCAN_KEY>
SEPOLIA_URL=https://eth-sepolia.alchemyapi.io/v2/<YOUR ALCHEMY KEY>
POLYGON_ZKEVM_TESTNET_URL=https://rpc.public.zkevm-test.net
PRIVATE_KEY=<YOUR_PRIVATE_KEY>
export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY"
export API_KEY_ARBISCAN="YOUR_API_KEY_ARBISCAN"
export API_KEY_BSCSCAN="YOUR_API_KEY_BSCSCAN"
export API_KEY_ETHERSCAN="YOUR_API_KEY_ETHERSCAN"
export API_KEY_GNOSISSCAN="YOUR_API_KEY_GNOSISSCAN"
export API_KEY_INFURA="YOUR_API_KEY_INFURA"
export API_KEY_OPTIMISTIC_ETHERSCAN="YOUR_API_KEY_OPTIMISTIC_ETHERSCAN"
export API_KEY_POLYGONSCAN="YOUR_API_KEY_POLYGONSCAN"
export API_KEY_SNOWTRACE="YOUR_API_KEY_SNOWTRACE"
export MNEMONIC="YOUR_MNEMONIC"
export FOUNDRY_PROFILE="default"

1
.gas-snapshot Normal file
View File

@ -0,0 +1 @@
FooTest:test_Example() (gas: 8662)

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
lib/** linguist-vendored

13
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,13 @@
## Description
Describe the changes made in your pull request here.
## Checklist
Ensure you completed **all of the steps** below before submitting your pull request:
- [ ] Added natspec comments?
- [ ] Ran `forge snapshot`?
- [ ] Ran `pnpm lint`?
- [ ] Ran `forge test`?
- [ ] Ran `pnpm verify`?

36
.github/scripts/rename.sh vendored Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca
set -euo pipefail
# Define the input vars
GITHUB_REPOSITORY=${1?Error: Please pass username/repo, e.g. prb/foundry-template}
GITHUB_REPOSITORY_OWNER=${2?Error: Please pass username, e.g. prb}
GITHUB_REPOSITORY_DESCRIPTION=${3:-""} # If null then replace with empty string
echo "GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
echo "GITHUB_REPOSITORY_OWNER: $GITHUB_REPOSITORY_OWNER"
echo "GITHUB_REPOSITORY_DESCRIPTION: $GITHUB_REPOSITORY_DESCRIPTION"
# jq is like sed for JSON data
JQ_OUTPUT=`jq \
--arg NAME "@$GITHUB_REPOSITORY" \
--arg AUTHOR_NAME "$GITHUB_REPOSITORY_OWNER" \
--arg URL "https://github.com/$GITHUB_REPOSITORY_OWNER" \
--arg DESCRIPTION "$GITHUB_REPOSITORY_DESCRIPTION" \
'.name = $NAME | .description = $DESCRIPTION | .author |= ( .name = $AUTHOR_NAME | .url = $URL )' \
package.json
`
# Overwrite package.json
echo "$JQ_OUTPUT" > package.json
# Make sed command compatible in both Mac and Linux environments
# Reference: https://stackoverflow.com/a/38595160/8696958
sedi () {
sed --version >/dev/null 2>&1 && sed -i -- "$@" || sed -i "" "$@"
}
# Rename instances of "vacp2p/foundry-template" to the new repo name in README.md for badges only
sedi "/gha/ s|vacp2p/foundry-template|"${GITHUB_REPOSITORY}"|;" "README.md"
sedi "/gha-badge/ s|vacp2p/foundry-template|"${GITHUB_REPOSITORY}"|;" "README.md"

View File

@ -1,60 +1,167 @@
name: CI
name: "CI"
env:
API_KEY_ALCHEMY: ${{ secrets.API_KEY_ALCHEMY }}
FOUNDRY_PROFILE: "ci"
on:
push:
branches: [main]
paths:
- "**.sol"
- "scripts/**.ts"
- "test/**.ts"
- "hardhat.config.ts"
- "package.json"
- ".github/workflows/ci.yml"
workflow_dispatch:
pull_request:
branches: [main]
paths:
- "**.sol"
- "scripts/**.ts"
- "test/**.ts"
- "hardhat.config.ts"
- "package.json"
- ".github/workflows/ci.yml"
push:
branches:
- "main"
jobs:
lint:
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- name: "Install Pnpm"
uses: "pnpm/action-setup@v2"
with:
version: "8"
- name: "Install Node.js"
uses: "actions/setup-node@v3"
with:
cache: "pnpm"
node-version: "lts/*"
- name: "Install the Node.js dependencies"
run: "pnpm install"
- name: "Lint the contracts"
run: "pnpm lint"
- name: "Add lint summary"
run: |
echo "## Lint result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
build:
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- name: "Build the contracts and print their size"
run: "forge build --sizes"
- name: "Add build summary"
run: |
echo "## Build result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
test:
needs: ["lint", "build"]
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- name: "Show the Foundry config"
run: "forge config"
- name: "Generate a fuzz seed that changes weekly to avoid burning through RPC allowance"
run: >
echo "FOUNDRY_FUZZ_SEED=$(
echo $(($EPOCHSECONDS - $EPOCHSECONDS % 604800))
)" >> $GITHUB_ENV
- name: "Run the tests"
run: "forge test"
- name: "Add test summary"
run: |
echo "## Tests result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
coverage:
needs: ["lint", "build"]
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
with:
submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- name: "Generate the coverage report using the unit and the integration tests"
run: 'forge coverage --match-path "test/**/*.sol" --report lcov'
- name: "Upload coverage report to Codecov"
uses: "codecov/codecov-action@v3"
with:
files: "./lcov.info"
- name: "Add coverage summary"
run: |
echo "## Coverage result" >> $GITHUB_STEP_SUMMARY
echo "✅ Uploaded to Codecov" >> $GITHUB_STEP_SUMMARY
verify:
needs: ["lint", "build"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Install Python
uses: actions/setup-python@v2
with: { python-version: 3.9 }
- name: Install Java
uses: actions/setup-java@v1
with: { java-version: "11", java-package: jre }
- name: Install Certora CLI
run: pip3 install certora-cli==5.0.5
- name: Install Solidity
run: |
wget https://github.com/ethereum/solidity/releases/download/v0.8.20/solc-static-linux
chmod +x solc-static-linux
sudo mv solc-static-linux /usr/local/bin/solc
- name: "Install Pnpm"
uses: "pnpm/action-setup@v2"
with:
version: nightly
version: "8"
- uses: actions/setup-node@v3
- name: "Install Node.js"
uses: "actions/setup-node@v3"
with:
node-version: 16
cache: "yarn"
- id: dependencies
run: yarn install
cache: "pnpm"
node-version: "lts/*"
- id: lint
run: yarn lint
- name: "Install the Node.js dependencies"
run: "pnpm install"
- id: test
run: yarn test:verbose
- name: Verify rules
run: "pnpm verify"
env:
CERTORAKEY: ${{ secrets.CERTORAKEY }}
- id: coverage
run: yarn coverage
- id: upload-coverage
# run only in pull requests
if: github.event_name == 'pull_request'
uses: zgosalvez/github-actions-report-lcov@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
coverage-files: lcov.info
artifact-name: code-coverage-report
strategy:
fail-fast: false
max-parallel: 16

52
.github/workflows/create.yml vendored Normal file
View File

@ -0,0 +1,52 @@
name: "Create"
# The workflow will run only when the "Use this template" button is used
on:
create:
jobs:
create:
# We only run this action when the repository isn't the template repository. References:
# - https://docs.github.com/en/actions/learn-github-actions/contexts
# - https://docs.github.com/en/actions/learn-github-actions/expressions
if: ${{ !github.event.repository.is_template }}
permissions: "write-all"
runs-on: "ubuntu-latest"
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- name: "Update package.json"
env:
GITHUB_REPOSITORY_DESCRIPTION: ${{ github.event.repository.description }}
run:
./.github/scripts/rename.sh "$GITHUB_REPOSITORY" "$GITHUB_REPOSITORY_OWNER" "$GITHUB_REPOSITORY_DESCRIPTION"
- name: "Add rename summary"
run: |
echo "## Commit result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
- name: "Remove files not needed in the user's copy of the template"
run: |
rm -f "./.github/FUNDING.yml"
rm -f "./.github/scripts/rename.sh"
rm -f "./.github/workflows/create.yml"
- name: "Add remove summary"
run: |
echo "## Remove result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
- name: "Update commit"
uses: "stefanzweifel/git-auto-commit-action@v4"
with:
commit_message: "feat: initial commit"
commit_options: "--amend"
push_options: "--force"
skip_fetch: true
- name: "Add commit summary"
run: |
echo "## Commit result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY

27
.gitignore vendored
View File

@ -1,14 +1,19 @@
node_modules
.env
coverage
coverage.json
typechain
#Hardhat files
# directories
cache
artifacts
#Foundry files
cache_forge
node_modules
out
# files
*.env
*.log
.DS_Store
.pnp.*
lcov.info
yarn.lock
# broadcasts
!broadcast
broadcast/*
broadcast/*/31337/
.certora_internal

2
.gitmodules vendored
View File

@ -1,4 +1,4 @@
[submodule "lib/forge-std"]
branch = "v1"
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.6.0

View File

@ -1,5 +1,18 @@
node_modules
artifacts
# directories
broadcast
cache
coverage*
gasReporterOutput.json
lib
node_modules
out
# files
*.env
*.log
.DS_Store
.pnp.*
lcov.info
package-lock.json
pnpm-lock.yaml
yarn.lock
slither.config.json

7
.prettierrc.yml Normal file
View File

@ -0,0 +1,7 @@
bracketSpacing: true
printWidth: 120
proseWrap: "always"
singleQuote: false
tabWidth: 2
trailingComma: "all"
useTabs: false

View File

@ -1,7 +1,13 @@
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["error", "^0.8.0"],
"func-visibility": ["warn", { "ignoreConstructors": true }]
"code-complexity": ["error", 8],
"compiler-version": ["error", ">=0.8.19"],
"func-name-mixedcase": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"named-parameters-mapping": "warn",
"no-console": "off",
"not-rely-on-time": "off"
}
}

16
LICENSE.md Normal file
View File

@ -0,0 +1,16 @@
MIT License
Copyright (c) 2023 Paul Razvan Berg
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

15
PROPERTIES.md Normal file
View File

@ -0,0 +1,15 @@
## Protocol properties and invariants
Below is a list of all documented properties and invariants of this project that must hold true.
- **Property** - Describes the property of the project / protocol that should ultimately be tested and formaly verified.
- **Type** - Properties are split into 5 main types: **Valid State**, **State Transition**, **Variable Transition**,
**High-Level Property**, **Unit Test**
- **Risk** - One of **High**, **Medium** and **Low**, depending on the property's risk factor
- **Tested** - Whether this property has been (fuzz) tested
| **Property** | **Type** | **Risk** | **Tested** |
| ------------ | -------- | -------- | ---------- |
| | | | |
| | | | |
| | | | |

211
README.md
View File

@ -1,60 +1,201 @@
# Hardhat Project for rln-contract
# Foundry Template [![Github Actions][gha-badge]][gha] [![Foundry][foundry-badge]][foundry] [![License: MIT][license-badge]][license]
## Requirements
[gha]: https://github.com/vacp2p/foundry-template/actions
[gha-badge]: https://github.com/vacp2p/foundry-template/actions/workflows/ci.yml/badge.svg
[foundry]: https://getfoundry.sh/
[foundry-badge]: https://img.shields.io/badge/Built%20with-Foundry-FFDB1C.svg
[license]: https://opensource.org/licenses/MIT
[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg
The following will need to be installed in order to use this repo. Please follow the links and instructions.
A Foundry-based template for developing Solidity smart contracts, with sensible defaults.
- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- You'll know you've done it right if you can run `git --version`
- [Foundry / Foundryup](https://github.com/gakonst/foundry)
- This will install `forge`, `cast`, and `anvil`
- You can test you've installed them right by running `forge --version` and get an output like: `forge 0.2.0 (92f8951 2022-08-06T00:09:32.96582Z)`
- To get the latest of each, just run `foundryup`
- [Yarn](https://classic.yarnpkg.com/lang/en/docs/install)
This is a fork of [PaulRBerg's template](https://github.com/PaulRBerg/foundry-template) and adjusted to Vac's smart
contracts unit's needs. See [Upstream differences](#upstream-differences) to learn more about how this template differs
from Paul's.
## Compilation
## What's Inside
```shell
yarn compile
- [Forge](https://github.com/foundry-rs/foundry/blob/master/forge): compile, test, fuzz, format, and deploy smart
contracts
- [Forge Std](https://github.com/foundry-rs/forge-std): collection of helpful contracts and cheatcodes for testing
- [Solhint Community](https://github.com/solhint-community/solhint-community): linter for Solidity code
## Getting Started
Click the [`Use this template`](https://github.com/vacp2p/foundry-template/generate) button at the top of the page to
create a new repository with this repo as the initial state.
Or, if you prefer to install the template manually:
```sh
$ mkdir my-project
$ cd my-project
$ forge init --template vacp2p/foundry-template
$ pnpm install # install Solhint, Prettier, and other Node.js deps
```
## Testing with Hardhat
If this is your first time with Foundry, check out the
[installation](https://github.com/foundry-rs/foundry#installation) instructions.
```shell
yarn test:hardhat
## Features
This template builds upon the frameworks and libraries mentioned above, so for details about their specific features,
please consult their respective documentation.
For example, if you're interested in exploring Foundry in more detail, you should look at the
[Foundry Book](https://book.getfoundry.sh/). In particular, you may be interested in reading the
[Writing Tests](https://book.getfoundry.sh/forge/writing-tests.html) tutorial.
### Upstream differences
As mentioned above, this template is a fork with adjustments specific to the needs of Vac's smart contract service unit.
These differences are:
- **Removal of [PRBTest](https://github.com/PaulRBerg/prb-test)** - In an attempt to keep dependence on third-party code
low, we've decided to remove this library as a standard dependency of every project within Vac. If we do see a need
for it, we might bring it back in the future.
- **PROPERTIES.md** - For invariant testing and formal verification, we've introduced a `PROPERTIES.md` to document all
protocol properties that must hold true.
### Sensible Defaults
This template comes with a set of sensible default configurations for you to use. These defaults can be found in the
following files:
```text
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc.yml
├── .solhint.json
├── foundry.toml
├── remappings.txt
└── slither.config.json
```
## Testing with Foundry
### VSCode Integration
```shell
yarn test:foundry
This template is IDE agnostic, but for the best user experience, you may want to use it in VSCode alongside Nomic
Foundation's [Solidity extension](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity).
For guidance on how to integrate a Foundry project in VSCode, please refer to this
[guide](https://book.getfoundry.sh/config/vscode).
### GitHub Actions
This template comes with GitHub Actions pre-configured. Your contracts will be linted and tested on every push and pull
request made to the `main` branch.
You can edit the CI script in [.github/workflows/ci.yml](./.github/workflows/ci.yml).
## Writing Tests
If you would like to view the logs in the terminal output you can add the `-vvv` flag and use
[console.log](https://book.getfoundry.sh/faq?highlight=console.log#how-do-i-use-consolelog).
This template comes with an example test contract [Foo.t.sol](./test/Foo.t.sol)
## Usage
This is a list of the most frequently needed commands.
### Build
Build the contracts:
```sh
$ forge build
```
## Deploying
### Clean
### Locally
Delete the build artifacts and cache directories:
- To deploy on a local node, first start the local node and then run the deploy script
```shell
yarn node
yarn deploy:localhost
```sh
$ forge clean
```
### Sepolia
### Compile
- To deploy to an target network (like Sepolia), use the name as mentioned in the Hardhat config file.
Compile the contracts:
```shell
yarn deploy:sepolia
# You may verify the contract using
yarn verify:sepolia # Ensure you have set ETHERSCAN_API_KEY in your env
```sh
$ forge build
```
## References
### Coverage
For more information, see https://hardhat.org/hardhat-runner/docs/guides/project-setup
Get a test coverage report:
```sh
$ forge coverage
```
### Deploy
Deploy to Anvil:
```sh
$ forge script script/Deploy.s.sol --broadcast --fork-url http://localhost:8545
```
For this script to work, you need to have a `MNEMONIC` environment variable set to a valid
[BIP39 mnemonic](https://iancoleman.io/bip39/).
For instructions on how to deploy to a testnet or mainnet, check out the
[Solidity Scripting](https://book.getfoundry.sh/tutorials/solidity-scripting.html) tutorial.
### Format
Format the contracts:
```sh
$ forge fmt
```
### Gas Usage
Get a gas report:
```sh
$ forge test --gas-report
```
### Lint
Lint the contracts:
```sh
$ pnpm lint
```
#### Fixing linting issues
For any errors in solidity files, run `forge fmt`. For errors in any other file type, run `pnpm prettier:write`.
### Test
Run the tests:
```sh
$ forge test
```
## Notes
1. Foundry uses [git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to manage dependencies. For
detailed instructions on working with dependencies, please refer to the
[guide](https://book.getfoundry.sh/projects/dependencies.html) in the book
2. You don't have to create a `.env` file, but filling in the environment variables may be useful when debugging and
testing against a fork.
## Related Efforts
- [abigger87/femplate](https://github.com/abigger87/femplate)
- [cleanunicorn/ethereum-smartcontract-template](https://github.com/cleanunicorn/ethereum-smartcontract-template)
- [foundry-rs/forge-template](https://github.com/foundry-rs/forge-template)
- [FrankieIsLost/forge-template](https://github.com/FrankieIsLost/forge-template)
## License
Dual-licensed under MIT or Apache 2.0, refer to [LICENSE-MIT](LICENSE-MIT) or [LICENSE-APACHE](LICENSE-APACHE) for more information.
This project is licensed under MIT.

8
certora/certora.conf Normal file
View File

@ -0,0 +1,8 @@
{
"files": ["src/Foo.sol"],
"msg": "Verifying Foo.sol",
"rule_sanity": "basic",
"verify": "Foo:certora/specs/Foo.spec",
"wait_for_results": "all",
}

9
certora/specs/Foo.spec Normal file
View File

@ -0,0 +1,9 @@
methods {
function id(uint256) external returns (uint256) envfree;
}
rule checkIdOutputIsAlwaysEqualToInput {
uint256 input;
assert id(input) == input;
}

28
codecov.yml Normal file
View File

@ -0,0 +1,28 @@
codecov:
require_ci_to_pass: false
comment: false
ignore:
- "script"
- "test"
coverage:
status:
project:
default:
# advanced settings
# Prevents PR from being blocked with a reduction in coverage.
# Note, if we want to re-enable this, a `threshold` value can be used
# allow coverage to drop by x% while still posting a success status.
# `informational`: https://docs.codecov.com/docs/commit-status#informational
# `threshold`: https://docs.codecov.com/docs/commit-status#threshold
informational: true
patch:
default:
# advanced settings
# Prevents PR from being blocked with a reduction in coverage.
# Note, if we want to re-enable this, a `threshold` value can be used
# allow coverage to drop by x% while still posting a success status.
# `informational`: https://docs.codecov.com/docs/commit-status#informational
# `threshold`: https://docs.codecov.com/docs/commit-status#threshold
informational: true

View File

@ -1,9 +0,0 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
pragma solidity 0.8.15;
interface IVerifier {
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[2] memory input)
external
view
returns (bool);
}

View File

@ -1,18 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "./RlnBase.sol";
contract RLN is RlnBase {
constructor(uint256 membershipDeposit, uint256 depth, address _verifier)
RlnBase(membershipDeposit, depth, _verifier)
{}
function _validateRegistration(uint256 idCommitment) internal pure override {}
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof)
internal
pure
override
{}
}

View File

@ -1,16 +0,0 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getUnnamedAccounts } = hre;
const { deploy } = deployments;
const [deployer] = await getUnnamedAccounts();
await deploy("PoseidonT3", {
from: deployer,
log: true,
});
};
export default func;
func.tags = ["PoseidonT3"];

View File

@ -1,16 +0,0 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getUnnamedAccounts } = hre;
const { deploy } = deployments;
const [deployer] = await getUnnamedAccounts();
await deploy("Verifier", {
from: deployer,
log: true,
});
};
export default func;
func.tags = ["RlnVerifier"];

View File

@ -1,21 +0,0 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getUnnamedAccounts } = hre;
const { deploy } = deployments;
const [deployer] = await getUnnamedAccounts();
await deploy("BinaryIMT", {
from: deployer,
log: true,
libraries: {
PoseidonT3: (await deployments.get("PoseidonT3")).address,
},
});
};
export default func;
func.tags = ["BinaryIMT"];
func.dependencies = ["PoseidonT3"];

View File

@ -1,26 +0,0 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getUnnamedAccounts } = hre;
const { deploy } = deployments;
const [deployer] = await getUnnamedAccounts();
const rlnVerifierAddress = (await deployments.get("Verifier")).address;
const binaryIMTAddress = (await deployments.get("BinaryIMT")).address;
await deploy("RLN", {
from: deployer,
log: true,
args: [1000000000000000, 20, rlnVerifierAddress],
libraries: {
BinaryIMT: binaryIMTAddress,
},
});
};
export default func;
func.tags = ["RLN"];
func.dependencies = ["PoseidonT3", "RlnVerifier", "BinaryIMT"];

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
1442

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
11155111

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,558 +0,0 @@
# Solidity API
## IVerifier
### verifyProof
```solidity
function verifyProof(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[2] input) external view returns (bool)
```
## RLN
### constructor
```solidity
constructor(uint256 membershipDeposit, uint256 depth, address _verifier) public
```
### \_validateRegistration
```solidity
function _validateRegistration(uint256 idCommitment) internal pure
```
_Inheriting contracts MUST override this function_
### \_validateSlash
```solidity
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] proof) internal pure
```
## FullTree
```solidity
error FullTree()
```
The tree is full
## InsufficientDeposit
```solidity
error InsufficientDeposit(uint256 required, uint256 provided)
```
Invalid deposit amount
### Parameters
| Name | Type | Description |
| -------- | ------- | --------------------------- |
| required | uint256 | The required deposit amount |
| provided | uint256 | The provided deposit amount |
## DuplicateIdCommitment
```solidity
error DuplicateIdCommitment()
```
Member is already registered
## FailedValidation
```solidity
error FailedValidation()
```
Failed validation on registration/slashing
## InvalidIdCommitment
```solidity
error InvalidIdCommitment(uint256 idCommitment)
```
Invalid idCommitment
## InvalidReceiverAddress
```solidity
error InvalidReceiverAddress(address to)
```
Invalid receiver address, when the receiver is the contract itself or 0x0
## MemberNotRegistered
```solidity
error MemberNotRegistered(uint256 idCommitment)
```
Member is not registered
## MemberHasNoStake
```solidity
error MemberHasNoStake(uint256 idCommitment)
```
Member has no stake
## InsufficientWithdrawalBalance
```solidity
error InsufficientWithdrawalBalance()
```
User has insufficient balance to withdraw
## InsufficientContractBalance
```solidity
error InsufficientContractBalance()
```
Contract has insufficient balance to return
## InvalidProof
```solidity
error InvalidProof()
```
Invalid proof
## InvalidPaginationQuery
```solidity
error InvalidPaginationQuery(uint256 startIndex, uint256 endIndex)
```
Invalid pagination query
## RlnBase
### Q
```solidity
uint256 Q
```
The Field
### MEMBERSHIP_DEPOSIT
```solidity
uint256 MEMBERSHIP_DEPOSIT
```
The deposit amount required to register as a member
### DEPTH
```solidity
uint256 DEPTH
```
The depth of the merkle tree
### SET_SIZE
```solidity
uint256 SET_SIZE
```
The size of the merkle tree, i.e 2^depth
### idCommitmentIndex
```solidity
uint256 idCommitmentIndex
```
The index of the next member to be registered
### stakedAmounts
```solidity
mapping(uint256 => uint256) stakedAmounts
```
The amount of eth staked by each member
maps from idCommitment to the amount staked
### members
```solidity
mapping(uint256 => uint256) members
```
The membership status of each member
maps from idCommitment to their index in the set
### indexToCommitment
```solidity
mapping(uint256 => uint256) indexToCommitment
```
the index to commitment mapping
### memberExists
```solidity
mapping(uint256 => bool) memberExists
```
The membership status of each member
### withdrawalBalance
```solidity
mapping(address => uint256) withdrawalBalance
```
The balance of each user that can be withdrawn
### verifier
```solidity
contract IVerifier verifier
```
The groth16 verifier contract
### deployedBlockNumber
```solidity
uint32 deployedBlockNumber
```
the deployed block number
### imtData
```solidity
struct BinaryIMTData imtData
```
the Incremental Merkle Tree
### MemberRegistered
```solidity
event MemberRegistered(uint256 idCommitment, uint256 index)
```
Emitted when a new member is added to the set
#### Parameters
| Name | Type | Description |
| ------------ | ------- | ---------------------------------- |
| idCommitment | uint256 | The idCommitment of the member |
| index | uint256 | The index of the member in the set |
### MemberWithdrawn
```solidity
event MemberWithdrawn(uint256 idCommitment, uint256 index)
```
Emitted when a member is removed from the set
#### Parameters
| Name | Type | Description |
| ------------ | ------- | ---------------------------------- |
| idCommitment | uint256 | The idCommitment of the member |
| index | uint256 | The index of the member in the set |
### onlyValidIdCommitment
```solidity
modifier onlyValidIdCommitment(uint256 idCommitment)
```
### constructor
```solidity
constructor(uint256 membershipDeposit, uint256 depth, address _verifier) internal
```
### register
```solidity
function register(uint256 idCommitment) external payable virtual
```
Allows a user to register as a member
#### Parameters
| Name | Type | Description |
| ------------ | ------- | ------------------------------ |
| idCommitment | uint256 | The idCommitment of the member |
### \_register
```solidity
function _register(uint256 idCommitment, uint256 stake) internal virtual
```
Registers a member
#### Parameters
| Name | Type | Description |
| ------------ | ------- | -------------------------------------- |
| idCommitment | uint256 | The idCommitment of the member |
| stake | uint256 | The amount of eth staked by the member |
### \_validateRegistration
```solidity
function _validateRegistration(uint256 idCommitment) internal view virtual
```
_Inheriting contracts MUST override this function_
### slash
```solidity
function slash(uint256 idCommitment, address payable receiver, uint256[8] proof) external virtual
```
_Allows a user to slash a member_
#### Parameters
| Name | Type | Description |
| ------------ | --------------- | ------------------------------ |
| idCommitment | uint256 | The idCommitment of the member |
| receiver | address payable | |
| proof | uint256[8] | |
### \_slash
```solidity
function _slash(uint256 idCommitment, address payable receiver, uint256[8] proof) internal virtual
```
_Slashes a member by removing them from the set, and adding their
stake to the receiver's available withdrawal balance_
#### Parameters
| Name | Type | Description |
| ------------ | --------------- | -------------------------------- |
| idCommitment | uint256 | The idCommitment of the member |
| receiver | address payable | The address to receive the funds |
| proof | uint256[8] | |
### \_validateSlash
```solidity
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] proof) internal view virtual
```
### withdraw
```solidity
function withdraw() external virtual
```
Allows a user to withdraw funds allocated to them upon slashing a member
### isValidCommitment
```solidity
function isValidCommitment(uint256 idCommitment) public pure returns (bool)
```
### \_verifyProof
```solidity
function _verifyProof(uint256 idCommitment, address receiver, uint256[8] proof) internal view virtual returns (bool)
```
_Groth16 proof verification_
### root
```solidity
function root() external view returns (uint256)
```
### getCommitments
```solidity
function getCommitments(uint256 startIndex, uint256 endIndex) public view returns (uint256[])
```
## Pairing
### G1Point
```solidity
struct G1Point {
uint256 X;
uint256 Y;
}
```
### G2Point
```solidity
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
```
### P1
```solidity
function P1() internal pure returns (struct Pairing.G1Point)
```
#### Return Values
| Name | Type | Description |
| ---- | ---------------------- | ------------------- |
| [0] | struct Pairing.G1Point | the generator of G1 |
### P2
```solidity
function P2() internal pure returns (struct Pairing.G2Point)
```
#### Return Values
| Name | Type | Description |
| ---- | ---------------------- | ------------------- |
| [0] | struct Pairing.G2Point | the generator of G2 |
### negate
```solidity
function negate(struct Pairing.G1Point p) internal pure returns (struct Pairing.G1Point r)
```
#### Return Values
| Name | Type | Description |
| ---- | ---------------------- | -------------------------------------------------------------- |
| r | struct Pairing.G1Point | the negation of p, i.e. p.addition(p.negate()) should be zero. |
### addition
```solidity
function addition(struct Pairing.G1Point p1, struct Pairing.G1Point p2) internal view returns (struct Pairing.G1Point r)
```
#### Return Values
| Name | Type | Description |
| ---- | ---------------------- | --------------------------- |
| r | struct Pairing.G1Point | the sum of two points of G1 |
### scalar_mul
```solidity
function scalar_mul(struct Pairing.G1Point p, uint256 s) internal view returns (struct Pairing.G1Point r)
```
#### Return Values
| Name | Type | Description |
| ---- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| r | struct Pairing.G1Point | the product of a point on G1 and a scalar, i.e. p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p. |
### pairing
```solidity
function pairing(struct Pairing.G1Point[] p1, struct Pairing.G2Point[] p2) internal view returns (bool)
```
#### Return Values
| Name | Type | Description |
| ---- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [0] | bool | the result of computing the pairing check e(p1[0], p2[0]) _ .... _ e(p1[n], p2[n]) == 1 For example pairing([P1(), P1().negate()], [P2(), P2()]) should return true. |
### pairingProd2
```solidity
function pairingProd2(struct Pairing.G1Point a1, struct Pairing.G2Point a2, struct Pairing.G1Point b1, struct Pairing.G2Point b2) internal view returns (bool)
```
Convenience method for a pairing check for two pairs.
### pairingProd3
```solidity
function pairingProd3(struct Pairing.G1Point a1, struct Pairing.G2Point a2, struct Pairing.G1Point b1, struct Pairing.G2Point b2, struct Pairing.G1Point c1, struct Pairing.G2Point c2) internal view returns (bool)
```
Convenience method for a pairing check for three pairs.
### pairingProd4
```solidity
function pairingProd4(struct Pairing.G1Point a1, struct Pairing.G2Point a2, struct Pairing.G1Point b1, struct Pairing.G2Point b2, struct Pairing.G1Point c1, struct Pairing.G2Point c2, struct Pairing.G1Point d1, struct Pairing.G2Point d2) internal view returns (bool)
```
Convenience method for a pairing check for four pairs.
## Verifier
### VerifyingKey
```solidity
struct VerifyingKey {
struct Pairing.G1Point alfa1;
struct Pairing.G2Point beta2;
struct Pairing.G2Point gamma2;
struct Pairing.G2Point delta2;
struct Pairing.G1Point[] IC;
}
```
### Proof
```solidity
struct Proof {
struct Pairing.G1Point A;
struct Pairing.G2Point B;
struct Pairing.G1Point C;
}
```
### verifyingKey
```solidity
function verifyingKey() internal pure returns (struct Verifier.VerifyingKey vk)
```
### verify
```solidity
function verify(uint256[] input, struct Verifier.Proof proof) internal view returns (uint256)
```
### verifyProof
```solidity
function verifyProof(uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[2] input) public view returns (bool r)
```
#### Return Values
| Name | Type | Description |
| ---- | ---- | --------------------------- |
| r | bool | bool true if proof is valid |

View File

@ -1,6 +1,39 @@
# Full reference https://github.com/foundry-rs/foundry/tree/master/config
[profile.default]
src = 'contracts'
out = 'out'
libs = ['node_modules', 'lib']
test = 'test'
cache_path = 'cache_forge'
auto_detect_solc = false
block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT
bytecode_hash = "none"
cbor_metadata = false
evm_version = "shanghai"
fuzz = { runs = 1_000 }
gas_reports = ["*"]
libs = ["lib"]
optimizer = true
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.19"
src = "src"
test = "test"
[profile.ci]
fuzz = { runs = 10_000 }
verbosity = 4
[etherscan]
sepolia = { key = "${API_KEY_ETHERSCAN}" }
[fmt]
bracket_spacing = true
int_types = "long"
line_length = 120
multiline_func_header = "all"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
wrap_comments = true
[rpc_endpoints]
localhost = "http://localhost:8545"
sepolia = "https://eth-sepolia.g.alchemy.com/v2/${SEPOLIA_API_KEY}"

View File

@ -1,75 +0,0 @@
import * as dotenv from "dotenv";
import { HardhatUserConfig } from "hardhat/config";
import { NetworksUserConfig } from "hardhat/types";
import "@nomicfoundation/hardhat-foundry";
import "hardhat-deploy";
import "@nomiclabs/hardhat-etherscan";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-waffle";
import "hardhat-gas-reporter";
import "solidity-docgen";
dotenv.config();
const {
SEPOLIA_URL,
PRIVATE_KEY,
ETHERSCAN_API_KEY,
POLYGON_ZKEVM_TESTNET_URL,
} = process.env;
const getNetworkConfig = (): NetworksUserConfig | undefined => {
if (
SEPOLIA_URL &&
PRIVATE_KEY &&
ETHERSCAN_API_KEY &&
POLYGON_ZKEVM_TESTNET_URL
) {
return {
sepolia: {
url: SEPOLIA_URL,
accounts: [PRIVATE_KEY],
forking: {
url: SEPOLIA_URL,
},
verify: {
etherscan: {
apiKey: ETHERSCAN_API_KEY,
apiUrl: "https://api-sepolia.etherscan.io",
},
},
},
polygonZkevmTestnet: {
url: POLYGON_ZKEVM_TESTNET_URL,
accounts: [PRIVATE_KEY],
forking: {
url: POLYGON_ZKEVM_TESTNET_URL,
},
},
localhost_integration: {
url: "http://localhost:8545",
},
};
}
return undefined;
};
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
const config: HardhatUserConfig = {
solidity: {
compilers: [
{
version: "0.8.15",
},
{
version: "0.6.11",
},
],
},
networks: getNetworkConfig(),
};
export default config;

View File

@ -1,53 +1,35 @@
{
"name": "rln-contract",
"license": "(MIT OR Apache-2.0)",
"scripts": {
"start": "hardhat node --export-all deployments/allDeployments.json",
"compile": "hardhat compile",
"test": "yarn test:foundry && yarn test:hardhat",
"test:verbose": "yarn test:foundry -vvv && yarn test:hardhat --verbose",
"test:hardhat": "hardhat test",
"test:hardhat:localhost": "yarn test:hardhat --network localhost",
"test:hardhat:sepolia": "yarn test:hardhat --network sepolia",
"test:foundry": "forge test",
"deploy": "hardhat deploy --export-all deployments/allDeployments.json --network",
"deploy:sepolia": "yarn deploy sepolia",
"deploy:polygon_zkevm_testnet": "yarn deploy polygonZkevmTestnet",
"deploy:localhost": "yarn deploy localhost",
"verify:sepolia": "hardhat --network sepolia etherscan-verify",
"coverage": "forge coverage --report lcov",
"fmt": "prettier --write \"**/*.{js,ts}\"",
"lint": "prettier --check \"**/*.{js,ts}\"",
"prepare": "husky install",
"docgen": "hardhat docgen"
"name": "@vacp2p/foundry-template",
"description": "Foundry-based template for developing Solidity smart contracts used by Vac",
"version": "1.0.0",
"author": {
"name": "0x-r4bbit",
"url": "https://github.com/vacp2p"
},
"devDependencies": {
"@nomicfoundation/hardhat-foundry": "^1.0.0",
"@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@types/chai": "^4.3.4",
"@types/mocha": "^9.1.1",
"@types/node": "^16.11.6",
"chai": "^4.3.6",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.7.2",
"hardhat": "^2.9.9",
"hardhat-deploy": "0.11.20",
"hardhat-gas-reporter": "^1.0.8",
"husky": "^8.0.2",
"lint-staged": "^13.0.3",
"solidity-docgen": "0.6.0-beta.35",
"ts-node": "^10.8.1",
"typescript": "^4.7.4"
"prettier": "^3.0.0",
"solhint-community": "^3.6.0"
},
"keywords": [
"blockchain",
"ethereum",
"forge",
"foundry",
"smart-contracts",
"solidity",
"template"
],
"private": true,
"scripts": {
"clean": "rm -rf cache out",
"lint": "pnpm lint:sol && pnpm prettier:check",
"verify": "certoraRun certora/certora.conf",
"lint:sol": "forge fmt --check && pnpm solhint {script,src,test,certora}/**/*.sol",
"prettier:check": "prettier --check **/*.{json,md,yml} --ignore-path=.prettierignore",
"prettier:write": "prettier --write **/*.{json,md,yml} --ignore-path=.prettierignore"
},
"dependencies": {
"@zk-kit/imt.sol": "^2.0.0-beta",
"dotenv": "^16.0.1"
},
"lint-staged": {
"**/*": [
"prettier --write --ignore-unknown"
]
"@zk-kit/imt.sol": "2.0.0-beta",
"poseidon-solidity": "^0.0.5"
}
}

470
pnpm-lock.yaml Normal file
View File

@ -0,0 +1,470 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@zk-kit/imt.sol':
specifier: 2.0.0-beta
version: 2.0.0-beta
poseidon-solidity:
specifier: ^0.0.5
version: 0.0.5
devDependencies:
prettier:
specifier: ^3.0.0
version: 3.0.0
solhint-community:
specifier: ^3.6.0
version: 3.6.0
packages:
/@babel/code-frame@7.22.5:
resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/highlight': 7.22.5
dev: true
/@babel/helper-validator-identifier@7.22.5:
resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
engines: {node: '>=6.9.0'}
dev: true
/@babel/highlight@7.22.5:
resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-validator-identifier': 7.22.5
chalk: 2.4.2
js-tokens: 4.0.0
dev: true
/@solidity-parser/parser@0.16.1:
resolution: {integrity: sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==}
dependencies:
antlr4ts: 0.5.0-alpha.4
dev: true
/@zk-kit/imt.sol@2.0.0-beta:
resolution: {integrity: sha512-bH7RvI5WHAEswUwPspUY582O2+71xbYv5aL+DM4xkaA0GdMyMLUwf5c1yJ4wrt46hp07iXCXJsLXdtLNsTnvZw==}
dependencies:
poseidon-solidity: 0.0.5
dev: false
/ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
dev: true
/ajv@8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
dev: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
dependencies:
color-convert: 1.9.3
dev: true
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: true
/antlr4@4.13.0:
resolution: {integrity: sha512-zooUbt+UscjnWyOrsuY/tVFL4rwrAGwOivpQmvmUDE22hy/lUA467Rc1rcixyRwcRUIXFYBwv7+dClDSHdmmew==}
engines: {node: '>=16'}
dev: true
/antlr4ts@0.5.0-alpha.4:
resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==}
dev: true
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/ast-parents@0.0.1:
resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==}
dev: true
/astral-regex@2.0.0:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: true
/chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
dependencies:
ansi-styles: 3.2.1
escape-string-regexp: 1.0.5
supports-color: 5.5.0
dev: true
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: true
/color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
color-name: 1.1.3
dev: true
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: true
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'}
dev: true
/cosmiconfig@8.2.0:
resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==}
engines: {node: '>=14'}
dependencies:
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
path-type: 4.0.0
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
is-arrayish: 0.2.1
dev: true
/escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
dev: true
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
dev: true
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 5.1.6
once: 1.4.0
dev: true
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
dev: true
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: true
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
dev: true
/import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
dev: true
/inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: true
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: true
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: true
/json-parse-even-better-errors@2.3.1:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: true
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true
/json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
dev: true
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
/lodash.truncate@4.4.2:
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
dev: true
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: true
/minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: true
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
dev: true
/parse-json@5.2.0:
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
engines: {node: '>=8'}
dependencies:
'@babel/code-frame': 7.22.5
error-ex: 1.3.2
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
dev: true
/path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
dev: true
/pluralize@8.0.0:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
dev: true
/poseidon-solidity@0.0.5:
resolution: {integrity: sha512-NzrvSwHzvZgT4hvg2GyGqeR+UOU/eLSEt4wAoXEua+VaR7NTKKwx1X9bPlh1VMBEVEno+IWvkRBbidFGzTeAqQ==}
dev: false
/prettier@2.8.8:
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
engines: {node: '>=10.13.0'}
hasBin: true
requiresBuild: true
dev: true
optional: true
/prettier@3.0.0:
resolution: {integrity: sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==}
engines: {node: '>=14'}
hasBin: true
dev: true
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
dev: true
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
dev: true
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: true
/semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
dev: true
/slice-ansi@4.0.0:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
dev: true
/solhint-community@3.6.0:
resolution: {integrity: sha512-3WGi8nB9VSdC7B3xawktFoQkJEgX6rsUe7jWZJteDBdix+tAOGN+2ZhRr7Cyv1s+h5BRLSsNOXoh7Vg9KEeQbg==}
hasBin: true
dependencies:
'@solidity-parser/parser': 0.16.1
ajv: 6.12.6
antlr4: 4.13.0
ast-parents: 0.0.1
chalk: 4.1.2
commander: 10.0.1
cosmiconfig: 8.2.0
fast-diff: 1.3.0
glob: 8.1.0
ignore: 5.2.4
js-yaml: 4.1.0
lodash: 4.17.21
pluralize: 8.0.0
semver: 6.3.1
strip-ansi: 6.0.1
table: 6.8.1
text-table: 0.2.0
optionalDependencies:
prettier: 2.8.8
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
dependencies:
has-flag: 3.0.0
dev: true
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: true
/table@6.8.1:
resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==}
engines: {node: '>=10.0.0'}
dependencies:
ajv: 8.12.0
lodash.truncate: 4.4.2
slice-ansi: 4.0.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: true
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
/uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.0
dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true

View File

@ -1,8 +1,3 @@
@ensdomains/=node_modules/@ensdomains/
ds-test/=lib/forge-std/lib/ds-test/src/
eth-gas-reporter/=node_modules/eth-gas-reporter/
forge-std/=lib/forge-std/src/
hardhat-deploy/=node_modules/hardhat-deploy/
hardhat/=node_modules/hardhat/
@zk-kit/imt.sol/=node_modules/@zk-kit/imt.sol/
poseidon-solidity/=node_modules/poseidon-solidity/

41
script/Base.s.sol Normal file
View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Script } from "forge-std/Script.sol";
abstract contract BaseScript is Script {
/// @dev Included to enable compilation of the script without a $MNEMONIC environment variable.
string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk";
/// @dev Needed for the deterministic deployments.
bytes32 internal constant ZERO_SALT = bytes32(0);
/// @dev The address of the transaction broadcaster.
address internal broadcaster;
/// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined.
string internal mnemonic;
/// @dev Initializes the transaction broadcaster like this:
///
/// - If $ETH_FROM is defined, use it.
/// - Otherwise, derive the broadcaster address from $MNEMONIC.
/// - If $MNEMONIC is not defined, default to a test mnemonic.
///
/// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line.
constructor() {
address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) });
if (from != address(0)) {
broadcaster = from;
} else {
mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC });
(broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 });
}
}
modifier broadcast() {
vm.startBroadcast(broadcaster);
_;
vm.stopBroadcast();
}
}

22
script/Deploy.s.sol Normal file
View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import { Verifier } from "../src/RlnVerifier.sol";
import { Rln } from "../src/Rln.sol";
import { BaseScript } from "./Base.s.sol";
import { DeploymentConfig } from "./DeploymentConfig.s.sol";
contract Deploy is BaseScript {
function run() public returns (Rln rln, DeploymentConfig deploymentConfig) {
deploymentConfig = new DeploymentConfig(broadcaster);
vm.startBroadcast(broadcaster);
// step 1: deploy the verifier
Verifier verifier = new Verifier();
// step 2: deploy the rln contract
rln = new Rln(0, 20, address(verifier));
vm.stopBroadcast();
}
}

View File

@ -0,0 +1,45 @@
//// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import { Script } from "forge-std/Script.sol";
contract DeploymentConfig is Script {
error DeploymentConfig_InvalidDeployerAddress();
error DeploymentConfig_NoConfigForChain(uint256);
struct NetworkConfig {
address deployer;
}
NetworkConfig public activeNetworkConfig;
address private deployer;
constructor(address _broadcaster) {
if (_broadcaster == address(0)) revert DeploymentConfig_InvalidDeployerAddress();
deployer = _broadcaster;
if (block.chainid == 31_337) {
activeNetworkConfig = getOrCreateAnvilEthConfig();
} else if (block.chainid == 11155111) {
activeNetworkConfig = getOrCreateSepoliaEthConfig();
} else {
revert DeploymentConfig_NoConfigForChain(block.chainid);
}
}
function getOrCreateAnvilEthConfig() public view returns (NetworkConfig memory) {
return NetworkConfig({ deployer: deployer });
}
function getOrCreateSepoliaEthConfig() public view returns (NetworkConfig memory) {
return NetworkConfig({ deployer: deployer });
}
// This function is a hack to have it excluded by `forge coverage` until
// https://github.com/foundry-rs/foundry/issues/2988 is fixed.
// See: https://github.com/foundry-rs/foundry/issues/2988#issuecomment-1437784542
// for more info.
// solhint-disable-next-line
function test() public { }
}

92
script/deploy.sh Executable file
View File

@ -0,0 +1,92 @@
#!/bin/bash
set -e
contract_name="$1"
if [ -z "$contract_name" ]; then
echo "Usage: ./script/deploy.sh <contract_name>"
exit 1
fi
echo "Sourcing .env"
source .env
# Check if appropriate env vars are set
if [ -z "$RPC_URL" ]; then
echo "RPC_URL is not set"
exit 1
fi
if [ -z "$PRIVATE_KEY" ]; then
echo "PRIVATE_KEY is not set"
exit 1
fi
echo "Deploying $contract_name..."
# Deploy the contract
if [ "$contract_name" = "rln" ]; then
chain_id=$(cast chain-id --rpc-url "$RPC_URL")
chain_name=""
verifier_url=""
if [ -z "$chain_id" ]; then
echo "Failed to get chain id"
exit 1
fi
if [ "$chain_id" = "11155111" ]; then
chain_name="sepolia"
else
echo "Invalid chain id, try again with sepolia"
exit 1
fi
forge script script/Deploy.s.sol:Deploy --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --broadcast -v --json
echo "Deployed Rln contracts, Now verifying"
# Get the PoseidonT3 contract address from ./broadcast/Deploy.s.sol/$chain_id/run-latest.json
poseidon_t3_name=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][0]["contractName"]')
poseidon_t3_address=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][0]["contractAddress"]')
echo "Verifying $poseidon_t3_name library"
forge verify-contract $poseidon_t3_address --chain $chain_name $poseidon_t3_name --watch
# Get the BinaryIMT contract address from ./broadcast/Deploy.s.sol/$chain_id/run-latest.json
binary_imt_name=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][1]["contractName"]')
binary_imt_address=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][1]["contractAddress"]')
echo "Verifying $binary_imt_name library"
forge verify-contract --libraries "poseidon-solidity/PoseidonT3.sol:$poseidon_t3_name:$poseidon_t3_address" $binary_imt_address --chain $chain_name $binary_imt_name --watch
# Get the Verifier contract address from ./broadcast/Deploy.s.sol/$chain_id/run-latest.json
verifier_name=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][2]["contractName"]')
verifier_address=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][2]["contractAddress"]')
echo "Verifying $verifier_name library"
forge verify-contract $verifier_address --chain $chain_name $verifier_name --watch
# Get the Rln contract address from ./broadcast/Deploy.s.sol/$chain_id/run-latest.json
rln_name=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][3]["contractName"]')
rln_address=$(cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"][3]["contractAddress"]')
echo "Verifying $rln_name library"
forge verify-contract \
$rln_address \
--libraries "poseidon-solidity/PoseidonT3.sol:$poseidon_t3_name:$poseidon_t3_address" \
--libraries "@zk-kit/imt.sol/BinaryIMT.sol:$binary_imt_name:$binary_imt_address" \
--chain $chain_name \
$rln_name \
--watch \
--constructor-args $(cast abi-encode "constructor(uint256,uint256,address)" 0 20 "$verifier_address")
echo "Verified $rln_name contract, now dumping the artifacts to ./deployments/$chain_id/latest.json"
# Dump the artifacts to ./deployments/$chain_id/latest.json
mkdir -p ./deployments/$chain_id
cat ./broadcast/Deploy.s.sol/$chain_id/run-latest.json | jq -r '.["transactions"]' > ./deployments/$chain_id/latest.json
else
echo "Invalid contract name, please use rln."
fi

View File

@ -1,3 +1,8 @@
{
"filter_paths": "contracts"
"detectors_to_exclude": "naming-convention,reentrancy-events,solc-version,timestamp",
"filter_paths": "(lib|test)",
"solc_remaps": [
"@openzeppelin/contracts=lib/openzeppelin-contracts/contracts/",
"forge-std/=lib/forge-std/src/"
]
}

14
src/IVerifier.sol Normal file
View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
pragma solidity ^0.8.15;
interface IVerifier {
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[2] memory input
)
external
view
returns (bool);
}

26
src/Rln.sol Normal file
View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "./RlnBase.sol";
contract Rln is RlnBase {
constructor(
uint256 membershipDeposit,
uint256 depth,
address _verifier
)
RlnBase(membershipDeposit, depth, _verifier)
{ }
function _validateRegistration(uint256 idCommitment) internal pure override { }
function _validateSlash(
uint256 idCommitment,
address payable receiver,
uint256[8] calldata proof
)
internal
pure
override
{ }
}

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
pragma solidity ^0.8.15;
import {IVerifier} from "./IVerifier.sol";
import {BinaryIMT, BinaryIMTData} from "@zk-kit/imt.sol/BinaryIMT.sol";
import { IVerifier } from "./IVerifier.sol";
import { BinaryIMT, BinaryIMTData } from "@zk-kit/imt.sol/BinaryIMT.sol";
/// The tree is full
error FullTree();
@ -45,7 +45,8 @@ error InvalidPaginationQuery(uint256 startIndex, uint256 endIndex);
abstract contract RlnBase {
/// @notice The Field
uint256 public constant Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 public constant Q =
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
/// @notice The deposit amount required to register as a member
uint256 public immutable MEMBERSHIP_DEPOSIT;
@ -141,7 +142,11 @@ abstract contract RlnBase {
/// @dev Allows a user to slash a member
/// @param idCommitment The idCommitment of the member
function slash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof)
function slash(
uint256 idCommitment,
address payable receiver,
uint256[8] calldata proof
)
external
virtual
onlyValidIdCommitment(idCommitment)
@ -185,7 +190,11 @@ abstract contract RlnBase {
emit MemberWithdrawn(idCommitment, index);
}
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof)
function _validateSlash(
uint256 idCommitment,
address payable receiver,
uint256[8] calldata proof
)
internal
view
virtual;
@ -209,7 +218,11 @@ abstract contract RlnBase {
}
/// @dev Groth16 proof verification
function _verifyProof(uint256 idCommitment, address receiver, uint256[8] calldata proof)
function _verifyProof(
uint256 idCommitment,
address receiver,
uint256[8] calldata proof
)
internal
view
virtual

View File

@ -1,8 +1,15 @@
// File: https://github.com/Rate-Limiting-Nullifier/rln-contract-v1/blob/main/src/RLNVerifier.sol
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// 2019 OKIMS
// ported to solidity 0.6
@ -11,7 +18,7 @@
//
//
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.11;
pragma solidity ^0.8.11;
library Pairing {
struct G1Point {
@ -35,12 +42,12 @@ library Pairing {
// Original code point
return G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634,
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531,
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930
]
);
@ -57,7 +64,8 @@ library Pairing {
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
// The prime q in the base field F_q for G1
uint256 q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
uint256 q =
21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583;
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
}
@ -108,7 +116,7 @@ library Pairing {
require(p1.length == p2.length, "pairing-lengths-failed");
uint256 elements = p1.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint[](inputSize);
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = p1[i].X;
input[i * 6 + 1] = p1[i].Y;
@ -131,7 +139,12 @@ library Pairing {
}
/// Convenience method for a pairing check for two pairs.
function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2)
function pairingProd2(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2
)
internal
view
returns (bool)
@ -153,7 +166,11 @@ library Pairing {
G2Point memory b2,
G1Point memory c1,
G2Point memory c2
) internal view returns (bool) {
)
internal
view
returns (bool)
{
G1Point[] memory p1 = new G1Point[](3);
G2Point[] memory p2 = new G2Point[](3);
p1[0] = a1;
@ -175,7 +192,11 @@ library Pairing {
G2Point memory c2,
G1Point memory d1,
G2Point memory d2
) internal view returns (bool) {
)
internal
view
returns (bool)
{
G1Point[] memory p1 = new G1Point[](4);
G2Point[] memory p2 = new G2Point[](4);
p1[0] = a1;
@ -209,60 +230,61 @@ contract Verifier {
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(
20491192805390485299153009773594534940189261866228447918068658471970481763042,
9383485363053290200918347156157836566562967994039712273449902621266178545958
20_491_192_805_390_485_299_153_009_773_594_534_940_189_261_866_228_447_918_068_658_471_970_481_763_042,
9_383_485_363_053_290_200_918_347_156_157_836_566_562_967_994_039_712_273_449_902_621_266_178_545_958
);
vk.beta2 = Pairing.G2Point(
[
4252822878758300859123897981450591353533073413197771768651442665752259397132,
6375614351688725206403948262868962793625744043794305715222011528459656738731
4_252_822_878_758_300_859_123_897_981_450_591_353_533_073_413_197_771_768_651_442_665_752_259_397_132,
6_375_614_351_688_725_206_403_948_262_868_962_793_625_744_043_794_305_715_222_011_528_459_656_738_731
],
[
21847035105528745403288232691147584728191162732299865338377159692350059136679,
10505242626370262277552901082094356697409835680220590971873171140371331206856
21_847_035_105_528_745_403_288_232_691_147_584_728_191_162_732_299_865_338_377_159_692_350_059_136_679,
10_505_242_626_370_262_277_552_901_082_094_356_697_409_835_680_220_590_971_873_171_140_371_331_206_856
]
);
vk.gamma2 = Pairing.G2Point(
[
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634,
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781
],
[
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531,
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930
]
);
vk.delta2 = Pairing.G2Point(
[
12423666958566268737444308034237892912702648013927558883280319245968679130649,
15986964528637281931410749976607406939789163617014270799373312764775965360012
12_423_666_958_566_268_737_444_308_034_237_892_912_702_648_013_927_558_883_280_319_245_968_679_130_649,
15_986_964_528_637_281_931_410_749_976_607_406_939_789_163_617_014_270_799_373_312_764_775_965_360_012
],
[
8394023076056524902583796202128496802110914536948580183128578071394816660799,
4964607673011101982600772762445991192038811950832626693345350322823626470007
8_394_023_076_056_524_902_583_796_202_128_496_802_110_914_536_948_580_183_128_578_071_394_816_660_799,
4_964_607_673_011_101_982_600_772_762_445_991_192_038_811_950_832_626_693_345_350_322_823_626_470_007
]
);
vk.IC = new Pairing.G1Point[](3);
vk.IC[0] = Pairing.G1Point(
1655549413518972190198478012616802994254462093161203201613599472264958303841,
21742734017792296281216385119397138748114275727065024271646515586404591497876
1_655_549_413_518_972_190_198_478_012_616_802_994_254_462_093_161_203_201_613_599_472_264_958_303_841,
21_742_734_017_792_296_281_216_385_119_397_138_748_114_275_727_065_024_271_646_515_586_404_591_497_876
);
vk.IC[1] = Pairing.G1Point(
16497930821522159474595176304955625435616718625609462506360632944366974274906,
10404924572941018678793755094259635830045501866471999610240845041996101882275
16_497_930_821_522_159_474_595_176_304_955_625_435_616_718_625_609_462_506_360_632_944_366_974_274_906,
10_404_924_572_941_018_678_793_755_094_259_635_830_045_501_866_471_999_610_240_845_041_996_101_882_275
);
vk.IC[2] = Pairing.G1Point(
9567910551099174794221497568036631681620409346997815381833929247558241020796,
17282591858786007768931802126325866705896012606427630592145070155065868649172
9_567_910_551_099_174_794_221_497_568_036_631_681_620_409_346_997_815_381_833_929_247_558_241_020_796,
17_282_591_858_786_007_768_931_802_126_325_866_705_896_012_606_427_630_592_145_070_155_065_868_649_172
);
}
function verify(uint256[] memory input, Proof memory proof) internal view returns (uint256) {
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 snark_scalar_field =
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.IC.length, "verifier-bad-input");
// Compute the linear combination vk_x
@ -281,7 +303,12 @@ contract Verifier {
}
/// @return r bool true if proof is valid
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[2] memory input)
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[2] memory input
)
public
view
returns (bool r)
@ -290,7 +317,7 @@ contract Verifier {
proof.A = Pairing.G1Point(a[0], a[1]);
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
proof.C = Pairing.G1Point(c[0], c[1]);
uint256[] memory inputValues = new uint[](input.length);
uint256[] memory inputValues = new uint256[](input.length);
for (uint256 i = 0; i < input.length; i++) {
inputValues[i] = input[i];
}

View File

@ -1,18 +0,0 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;
import "poseidon-solidity/PoseidonT3.sol";
import "forge-std/Test.sol";
contract PoseidonHasherTest is Test {
/// @dev Setup the testing environment.
function setUp() public {}
/// @dev Ensure that you can hash a value.
function testHasher() public {
assertEq(
PoseidonT3.hash([19014214495641488759237505126948346942972912379615652741039992445865937985820, 0]),
13164376930590487041313497514223288845711140604177161029957349518915056324115
);
}
}

View File

@ -1,70 +0,0 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;
import "../contracts/RlnBase.sol";
import "./Verifier.sol";
import "forge-std/Test.sol";
import "forge-std/StdCheats.sol";
import "forge-std/console.sol";
contract RlnApp is RlnBase {
uint256 public constant allowedIdCommitment =
19014214495641488759237505126948346942972912379615652741039992445865937985820;
uint256 private membershipDeposit = 1000000000000000;
uint256 private depth = 20;
constructor(address _verifier) RlnBase(membershipDeposit, depth, _verifier) {}
function _validateRegistration(uint256 idCommitment) internal pure override {
if (idCommitment != allowedIdCommitment) revert FailedValidation();
}
function _validateSlash(uint256 idCommitment, address payable receiver, uint256[8] calldata proof)
internal
pure
override
{
if (idCommitment == allowedIdCommitment) revert FailedValidation();
}
}
contract RLNAppTest is Test {
RlnApp public rlnApp;
TrueVerifier public trueVerifier;
uint256 public constant MEMBERSHIP_DEPOSIT = 1000000000000000;
uint256 public constant DEPTH = 20;
uint256 public constant SET_SIZE = 1048576;
uint256[8] public zeroedProof = [0, 0, 0, 0, 0, 0, 0, 0];
function setUp() public {
trueVerifier = new TrueVerifier();
rlnApp = new RlnApp(address(trueVerifier));
}
function test__Constants() public {
// sanity checking
assertEq(rlnApp.MEMBERSHIP_DEPOSIT(), MEMBERSHIP_DEPOSIT);
assertEq(rlnApp.DEPTH(), DEPTH);
assertEq(rlnApp.SET_SIZE(), SET_SIZE);
}
function test__InvalidRegistration(uint256 idCommitment) public {
vm.assume(idCommitment != rlnApp.allowedIdCommitment());
vm.assume(rlnApp.isValidCommitment(idCommitment));
vm.expectRevert(FailedValidation.selector);
rlnApp.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
}
function test__ValidRegistration() public {
rlnApp.register{value: MEMBERSHIP_DEPOSIT}(rlnApp.allowedIdCommitment());
}
function test__InvalidSlash() public {
uint256 allowedIdCommitment = rlnApp.allowedIdCommitment();
rlnApp.register{value: MEMBERSHIP_DEPOSIT}(allowedIdCommitment);
vm.expectRevert(FailedValidation.selector);
rlnApp.slash(allowedIdCommitment, payable(address(this)), zeroedProof);
}
}

View File

@ -1,31 +1,34 @@
// SPDX-License-Identifier: Unlicense
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "../contracts/Rln.sol";
import "./Verifier.sol";
import "forge-std/Test.sol";
import { Test, console } from "forge-std/Test.sol";
import "forge-std/StdCheats.sol";
import "forge-std/console.sol";
import { TrueVerifier, FalseVerifier } from "./mocks/VerifierMock.sol";
import { Deploy } from "../script/Deploy.s.sol";
import { DeploymentConfig } from "../script/DeploymentConfig.s.sol";
import "../src/Rln.sol";
contract RlnTest is Test {
using stdStorage for StdStorage;
RLN public rln;
TrueVerifier public trueVerifier;
FalseVerifier public falseVerifier;
Rln internal rln;
TrueVerifier internal trueVerifier;
FalseVerifier internal falseVerifier;
uint256 public constant MEMBERSHIP_DEPOSIT = 1000000000000000;
uint256 public constant DEPTH = 20;
uint256 public constant SET_SIZE = 1048576;
uint256[8] public zeroedProof = [0, 0, 0, 0, 0, 0, 0, 0];
/// @dev Setup the testing environment.
function setUp() public {
function setUp() public virtual {
trueVerifier = new TrueVerifier();
falseVerifier = new FalseVerifier();
rln = new RLN(MEMBERSHIP_DEPOSIT, DEPTH, address(trueVerifier));
rln = new Rln(MEMBERSHIP_DEPOSIT, DEPTH, address(trueVerifier));
}
uint256 public constant MEMBERSHIP_DEPOSIT = 1_000_000_000_000_000;
uint256 public constant DEPTH = 20;
uint256 public constant SET_SIZE = 1_048_576;
uint256[8] public zeroedProof = [0, 0, 0, 0, 0, 0, 0, 0];
/// @dev Ensure that you can hash a value.
function test__Constants() public {
assertEq(rln.MEMBERSHIP_DEPOSIT(), MEMBERSHIP_DEPOSIT);
@ -36,7 +39,7 @@ contract RlnTest is Test {
function test__ValidRegistration(uint256 idCommitment) public {
vm.assume(rln.isValidCommitment(idCommitment));
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
assertEq(rln.memberExists(idCommitment), true);
assertEq(rln.members(idCommitment), 0);
@ -44,40 +47,36 @@ contract RlnTest is Test {
function test__InvalidRegistration__DuplicateCommitment(uint256 idCommitment) public {
vm.assume(rln.isValidCommitment(idCommitment));
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
assertEq(rln.memberExists(idCommitment), true);
assertEq(rln.members(idCommitment), 0);
vm.expectRevert(DuplicateIdCommitment.selector);
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
}
function test__InvalidRegistration__InvalidIdCommitment(uint256 idCommitment) public {
vm.assume(!rln.isValidCommitment(idCommitment));
vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, idCommitment));
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
}
function test__InvalidRegistration__InsufficientDeposit(uint256 idCommitment) public {
vm.assume(rln.isValidCommitment(idCommitment));
uint256 badDepositAmount = MEMBERSHIP_DEPOSIT - 1;
vm.expectRevert(abi.encodeWithSelector(InsufficientDeposit.selector, MEMBERSHIP_DEPOSIT, badDepositAmount));
rln.register{value: badDepositAmount}(idCommitment);
rln.register{ value: badDepositAmount }(idCommitment);
}
function test__InvalidRegistration__FullSet() public {
RLN tempRln = new RLN(
MEMBERSHIP_DEPOSIT,
2,
address(rln.verifier())
);
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, address(rln.verifier()));
uint256 setSize = tempRln.SET_SIZE();
for (uint256 i = 1; i <= setSize; i++) {
tempRln.register{value: MEMBERSHIP_DEPOSIT}(i);
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(i);
}
assertEq(tempRln.idCommitmentIndex(), 4);
vm.expectRevert(FullTree.selector);
tempRln.register{value: MEMBERSHIP_DEPOSIT}(setSize + 1);
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(setSize + 1);
}
function test__ValidSlash(uint256 idCommitment, address payable to) public {
@ -88,7 +87,7 @@ contract RlnTest is Test {
vm.assume(to != address(0));
vm.assume(rln.isValidCommitment(idCommitment));
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
uint256 balanceBefore = to.balance;
@ -103,17 +102,19 @@ contract RlnTest is Test {
}
function test__InvalidSlash__ToZeroAddress() public {
uint256 idCommitment = 9014214495641488759237505126948346942972912379615652741039992445865937985820;
uint256 idCommitment =
9_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
vm.expectRevert(abi.encodeWithSelector(InvalidReceiverAddress.selector, address(0)));
rln.slash(idCommitment, payable(address(0)), zeroedProof);
}
function test__InvalidSlash__ToRlnAddress() public {
uint256 idCommitment = 19014214495641488759237505126948346942972912379615652741039992445865937985820;
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
uint256 idCommitment =
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
vm.expectRevert(abi.encodeWithSelector(InvalidReceiverAddress.selector, address(rln)));
rln.slash(idCommitment, payable(address(rln)), zeroedProof);
@ -133,7 +134,7 @@ contract RlnTest is Test {
vm.assume(to != address(0));
vm.assume(rln.isValidCommitment(idCommitment));
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
rln.slash(idCommitment, to, zeroedProof);
@ -148,15 +149,12 @@ contract RlnTest is Test {
}
function test__InvalidSlash__InvalidProof() public {
uint256 idCommitment = 19014214495641488759237505126948346942972912379615652741039992445865937985820;
uint256 idCommitment =
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
RLN tempRln = new RLN(
MEMBERSHIP_DEPOSIT,
2,
address(falseVerifier)
);
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, address(falseVerifier));
tempRln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
vm.expectRevert(InvalidProof.selector);
tempRln.slash(idCommitment, payable(address(this)), zeroedProof);
@ -168,8 +166,9 @@ contract RlnTest is Test {
}
function test__InvalidWithdraw__InsufficientContractBalance() public {
uint256 idCommitment = 19014214495641488759237505126948346942972912379615652741039992445865937985820;
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
uint256 idCommitment =
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
rln.slash(idCommitment, payable(address(this)), zeroedProof);
assertEq(rln.stakedAmounts(idCommitment), 0);
@ -185,9 +184,10 @@ contract RlnTest is Test {
assumeNotPrecompile(to);
vm.assume(to != address(0));
uint256 idCommitment = 19014214495641488759237505126948346942972912379615652741039992445865937985820;
uint256 idCommitment =
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitment);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
rln.slash(idCommitment, to, zeroedProof);
assertEq(rln.stakedAmounts(idCommitment), 0);
@ -201,42 +201,65 @@ contract RlnTest is Test {
function test__root() public {
uint256[] memory idCommitments = new uint256[](10);
idCommitments[0] = 19143711682366759980911001457853255795836264632723844153354310748778748156460;
idCommitments[1] = 16984765328852711772291441487727981184905800779020079168989152080434188364678;
idCommitments[2] = 10972315136095845343447418815139813428649316683283020632475608655814722712541;
idCommitments[3] = 2709631781045191277266130708832884002577134582503944059038971337978087532997;
idCommitments[4] = 8255654132980945447086418574686169461187805238257784695584517016324877809505;
idCommitments[5] = 20291701150251695209910387548168084091751201746043024067531503187703236470983;
idCommitments[6] = 11817872986033932471261438074921403500882957864164537515599299873089437746577;
idCommitments[7] = 18475838919635792169148272767721284591038756730004222133003018558598315558783;
idCommitments[8] = 10612118277928165031660389522171737855229037400929675201853245490188277695983;
idCommitments[9] = 17318633845296358766427229711888486415250435256643711009388405482885762601797;
idCommitments[0] =
19_143_711_682_366_759_980_911_001_457_853_255_795_836_264_632_723_844_153_354_310_748_778_748_156_460;
idCommitments[1] =
16_984_765_328_852_711_772_291_441_487_727_981_184_905_800_779_020_079_168_989_152_080_434_188_364_678;
idCommitments[2] =
10_972_315_136_095_845_343_447_418_815_139_813_428_649_316_683_283_020_632_475_608_655_814_722_712_541;
idCommitments[3] =
2_709_631_781_045_191_277_266_130_708_832_884_002_577_134_582_503_944_059_038_971_337_978_087_532_997;
idCommitments[4] =
8_255_654_132_980_945_447_086_418_574_686_169_461_187_805_238_257_784_695_584_517_016_324_877_809_505;
idCommitments[5] =
20_291_701_150_251_695_209_910_387_548_168_084_091_751_201_746_043_024_067_531_503_187_703_236_470_983;
idCommitments[6] =
11_817_872_986_033_932_471_261_438_074_921_403_500_882_957_864_164_537_515_599_299_873_089_437_746_577;
idCommitments[7] =
18_475_838_919_635_792_169_148_272_767_721_284_591_038_756_730_004_222_133_003_018_558_598_315_558_783;
idCommitments[8] =
10_612_118_277_928_165_031_660_389_522_171_737_855_229_037_400_929_675_201_853_245_490_188_277_695_983;
idCommitments[9] =
17_318_633_845_296_358_766_427_229_711_888_486_415_250_435_256_643_711_009_388_405_482_885_762_601_797;
vm.pauseGasMetering();
for (uint256 i = 0; i < idCommitments.length; i++) {
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitments[i]);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitments[i]);
}
vm.resumeGasMetering();
assertEq(rln.root(), 5210724218081541877101688952118136930297124697603087561558225712176057209122);
assertEq(
rln.root(),
5_210_724_218_081_541_877_101_688_952_118_136_930_297_124_697_603_087_561_558_225_712_176_057_209_122
);
}
function test__paginationCommitments() public {
uint256[] memory idCommitments = new uint256[](10);
idCommitments[0] = 19143711682366759980911001457853255795836264632723844153354310748778748156460;
idCommitments[1] = 16984765328852711772291441487727981184905800779020079168989152080434188364678;
idCommitments[2] = 10972315136095845343447418815139813428649316683283020632475608655814722712541;
idCommitments[3] = 2709631781045191277266130708832884002577134582503944059038971337978087532997;
idCommitments[4] = 8255654132980945447086418574686169461187805238257784695584517016324877809505;
idCommitments[5] = 20291701150251695209910387548168084091751201746043024067531503187703236470983;
idCommitments[6] = 11817872986033932471261438074921403500882957864164537515599299873089437746577;
idCommitments[7] = 18475838919635792169148272767721284591038756730004222133003018558598315558783;
idCommitments[8] = 10612118277928165031660389522171737855229037400929675201853245490188277695983;
idCommitments[9] = 17318633845296358766427229711888486415250435256643711009388405482885762601797;
idCommitments[0] =
19_143_711_682_366_759_980_911_001_457_853_255_795_836_264_632_723_844_153_354_310_748_778_748_156_460;
idCommitments[1] =
16_984_765_328_852_711_772_291_441_487_727_981_184_905_800_779_020_079_168_989_152_080_434_188_364_678;
idCommitments[2] =
10_972_315_136_095_845_343_447_418_815_139_813_428_649_316_683_283_020_632_475_608_655_814_722_712_541;
idCommitments[3] =
2_709_631_781_045_191_277_266_130_708_832_884_002_577_134_582_503_944_059_038_971_337_978_087_532_997;
idCommitments[4] =
8_255_654_132_980_945_447_086_418_574_686_169_461_187_805_238_257_784_695_584_517_016_324_877_809_505;
idCommitments[5] =
20_291_701_150_251_695_209_910_387_548_168_084_091_751_201_746_043_024_067_531_503_187_703_236_470_983;
idCommitments[6] =
11_817_872_986_033_932_471_261_438_074_921_403_500_882_957_864_164_537_515_599_299_873_089_437_746_577;
idCommitments[7] =
18_475_838_919_635_792_169_148_272_767_721_284_591_038_756_730_004_222_133_003_018_558_598_315_558_783;
idCommitments[8] =
10_612_118_277_928_165_031_660_389_522_171_737_855_229_037_400_929_675_201_853_245_490_188_277_695_983;
idCommitments[9] =
17_318_633_845_296_358_766_427_229_711_888_486_415_250_435_256_643_711_009_388_405_482_885_762_601_797;
vm.pauseGasMetering();
for (uint256 i = 0; i < idCommitments.length; i++) {
rln.register{value: MEMBERSHIP_DEPOSIT}(idCommitments[i]);
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitments[i]);
}
vm.resumeGasMetering();

View File

@ -1,24 +0,0 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;
import {IVerifier} from "../contracts/IVerifier.sol";
contract TrueVerifier is IVerifier {
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[2] memory input)
external
pure
returns (bool)
{
return true;
}
}
contract FalseVerifier is IVerifier {
function verifyProof(uint256[2] memory a, uint256[2][2] memory b, uint256[2] memory c, uint256[2] memory input)
external
pure
returns (bool)
{
return false;
}
}

View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;
import { IVerifier } from "../../src/IVerifier.sol";
contract TrueVerifier is IVerifier {
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[2] memory input
)
external
pure
returns (bool)
{
return true;
}
}
contract FalseVerifier is IVerifier {
function verifyProof(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[2] memory input
)
external
pure
returns (bool)
{
return false;
}
}

View File

@ -1,22 +0,0 @@
import { expect } from "chai";
import { ethers, deployments } from "hardhat";
describe("PoseidonT3", () => {
beforeEach(async () => {
await deployments.fixture(["PoseidonT3"]);
});
it("should hash correctly", async function () {
const poseidonHasher = await ethers.getContract("PoseidonT3");
// We test hashing for a random number
const hash = await poseidonHasher.hash([
"19014214495641488759237505126948346942972912379615652741039992445865937985820",
"0",
]);
expect(hash.toHexString()).to.eql(
"0x1d1ac5f6cf23b059eb43c657ce622b614b5960ea4b23f92d428d3e42982a4e13"
);
});
});

View File

@ -1,78 +0,0 @@
import { expect } from "chai";
import { ethers, deployments } from "hardhat";
describe("Rln", () => {
beforeEach(async () => {
await deployments.fixture(["RLN"]);
});
it("should register new memberships", async () => {
const rln = await ethers.getContract("RLN", ethers.provider.getSigner(0));
const price = await rln.MEMBERSHIP_DEPOSIT();
// A valid pair of (id_secret, id_commitment) generated in rust
const idCommitment =
"0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368";
const registerTx = await rln["register(uint256)"](idCommitment, {
value: price,
});
const txRegisterReceipt = await registerTx.wait();
const pubkey = txRegisterReceipt.events[0].args.idCommitment;
// We ensure the registered id_commitment is the one we passed
expect(
pubkey.toHexString() === idCommitment,
"registered commitment doesn't match passed commitment"
);
});
it("should slash membership", async () => {
const rln = await ethers.getContract("RLN", ethers.provider.getSigner(0));
const price = await rln.MEMBERSHIP_DEPOSIT();
// A valid id_commitment generated in zerokit
const idCommitment =
"0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368";
const registerTx = await rln["register(uint256)"](idCommitment, {
value: price,
});
await registerTx.wait();
// We slash the id_commitment
const receiverAddress = "0x000000000000000000000000000000000000dead";
const slashTx = rln["slash(uint256,address,uint256[8])"](
idCommitment,
receiverAddress,
[0, 0, 0, 0, 0, 0, 0, 0]
);
await expect(slashTx).to.be.revertedWith("InvalidProof()");
});
it("should not allow multiple registrations with same pubkey", async () => {
const rln = await ethers.getContract("RLN", ethers.provider.getSigner(0));
const price = await rln.MEMBERSHIP_DEPOSIT();
// A valid pair of (id_secret, id_commitment) generated in rust
const idCommitment =
"0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368";
const registerTx = await rln["register(uint256)"](idCommitment, {
value: price,
});
await registerTx.wait();
// Send the same tx again
const registerTx2 = rln["register(uint256)"](idCommitment, {
value: price,
});
await expect(registerTx2).to.be.revertedWith("DuplicateIdCommitment()");
});
});

View File

@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist",
"declaration": true
},
"include": [
"./scripts",
"./test",
"./typechain",
"deploy"
],
"files": [
"./hardhat.config.ts"
]
}

9349
yarn.lock

File diff suppressed because it is too large Load Diff