diff --git a/.solcover.js b/.solcover.js index 7d5b4de..884606c 100644 --- a/.solcover.js +++ b/.solcover.js @@ -1,4 +1,4 @@ module.exports = { - istanbulReporter: ['lcov'], - istanbulFolder: 'coverage', -} \ No newline at end of file + istanbulReporter: ["lcov"], + istanbulFolder: "coverage", +}; diff --git a/common/chain-utils.ts b/common/chain-utils.ts index ea7ca99..5c816bb 100644 --- a/common/chain-utils.ts +++ b/common/chain-utils.ts @@ -1,9 +1,5 @@ -export const devNets = [ - 'hardhat', - 'localhost', - 'goerli', -] +export const devNets = ["hardhat", "localhost", "goerli"]; -export const prodNets = ['mainnet'] +export const prodNets = ["mainnet"]; -export const isDevNet = (networkName: string) => devNets.includes(networkName) \ No newline at end of file +export const isDevNet = (networkName: string) => devNets.includes(networkName); diff --git a/common/index.ts b/common/index.ts index 2a7e063..1da4bb2 100644 --- a/common/index.ts +++ b/common/index.ts @@ -1,3 +1,3 @@ // barrel for all other utils -export * from './interep-utils'; -export * from './chain-utils'; \ No newline at end of file +export * from "./interep-utils"; +export * from "./chain-utils"; diff --git a/common/interep-utils.ts b/common/interep-utils.ts index de67650..90c5cb6 100644 --- a/common/interep-utils.ts +++ b/common/interep-utils.ts @@ -1,33 +1,42 @@ -import {utils} from "ethers"; +import { utils } from "ethers"; export const sToBytes32 = (str: string): string => { - return utils.formatBytes32String(str); -} + return utils.formatBytes32String(str); +}; export const SNARK_SCALAR_FIELD = BigInt( - "21888242871839275222246405745257275088548364400416034343698204186575808495617" -) + "21888242871839275222246405745257275088548364400416034343698204186575808495617" +); export const createGroupId = (provider: string, name: string): bigint => { - const providerBytes = sToBytes32(provider); - const nameBytes = sToBytes32(name); - return BigInt(utils.solidityKeccak256(["bytes32", "bytes32"], [providerBytes, nameBytes])) % SNARK_SCALAR_FIELD -} + const providerBytes = sToBytes32(provider); + const nameBytes = sToBytes32(name); + return ( + BigInt( + utils.solidityKeccak256( + ["bytes32", "bytes32"], + [providerBytes, nameBytes] + ) + ) % SNARK_SCALAR_FIELD + ); +}; -const providers = ['github', 'twitter', 'reddit']; -const tiers = ['bronze', 'silver', 'gold']; +const providers = ["github", "twitter", "reddit"]; +const tiers = ["bronze", "silver", "gold"]; export const getGroups = () => { - return providers.flatMap(provider => tiers.map(tier => { - return { - provider: sToBytes32(provider), - name: sToBytes32(tier), - root: 1, - depth: 10, - } - })); -} + return providers.flatMap((provider) => + tiers.map((tier) => { + return { + provider: sToBytes32(provider), + name: sToBytes32(tier), + root: 1, + depth: 10, + }; + }) + ); +}; export const getValidGroups = () => { - return getGroups().filter(group => group.name !== sToBytes32('bronze')); -} \ No newline at end of file + return getGroups().filter((group) => group.name !== sToBytes32("bronze")); +}; diff --git a/deploy/001_deploy_poseidon_hasher.ts b/deploy/001_deploy_poseidon_hasher.ts index d555438..e7e4773 100644 --- a/deploy/001_deploy_poseidon_hasher.ts +++ b/deploy/001_deploy_poseidon_hasher.ts @@ -1,16 +1,16 @@ -import {HardhatRuntimeEnvironment} from 'hardhat/types'; -import {DeployFunction} from 'hardhat-deploy/types'; +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('PoseidonHasher', { - from: deployer, - log: true, - }); + const { deployments, getUnnamedAccounts } = hre; + const { deploy } = deployments; + + const [deployer] = await getUnnamedAccounts(); + + await deploy("PoseidonHasher", { + from: deployer, + log: true, + }); }; export default func; -func.tags = ['PoseidonHasher']; \ No newline at end of file +func.tags = ["PoseidonHasher"]; diff --git a/deploy/002_deploy_interep_test.ts b/deploy/002_deploy_interep_test.ts index d4cf9d3..c66d8f1 100644 --- a/deploy/002_deploy_interep_test.ts +++ b/deploy/002_deploy_interep_test.ts @@ -1,35 +1,33 @@ -import {HardhatRuntimeEnvironment} from 'hardhat/types'; -import {DeployFunction} from 'hardhat-deploy/types'; -import { - getGroups, - isDevNet -} from '../common'; - +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; +import { getGroups, isDevNet } from "../common"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getUnnamedAccounts} = hre; - const {deploy} = deployments; - - const [deployer] = await getUnnamedAccounts(); - - const interepTest = await deploy('InterepTest', { - from: deployer, - log: true, - args: [], - }); + const { deployments, getUnnamedAccounts } = hre; + const { deploy } = deployments; - const contract = await hre.ethers.getContractAt('InterepTest', interepTest.address); - const groups = getGroups(); - const groupInsertionTx = await contract.updateGroups(groups); - await groupInsertionTx.wait(); - + const [deployer] = await getUnnamedAccounts(); + + const interepTest = await deploy("InterepTest", { + from: deployer, + log: true, + args: [], + }); + + const contract = await hre.ethers.getContractAt( + "InterepTest", + interepTest.address + ); + const groups = getGroups(); + const groupInsertionTx = await contract.updateGroups(groups); + await groupInsertionTx.wait(); }; export default func; -func.tags = ['InterepTest']; +func.tags = ["InterepTest"]; // skip when running on mainnet func.skip = async (hre: HardhatRuntimeEnvironment) => { - if (isDevNet(hre.network.name)) { - return false; - } - return true; -} \ No newline at end of file + if (isDevNet(hre.network.name)) { + return false; + } + return true; +}; diff --git a/deploy/003_deploy_valid_group_storage.ts b/deploy/003_deploy_valid_group_storage.ts index cdfd070..cffba3c 100644 --- a/deploy/003_deploy_valid_group_storage.ts +++ b/deploy/003_deploy_valid_group_storage.ts @@ -1,24 +1,26 @@ -import {HardhatRuntimeEnvironment} from 'hardhat/types'; -import {DeployFunction} from 'hardhat-deploy/types'; -import {getValidGroups, isDevNet} from '../common'; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; +import { getValidGroups, isDevNet } from "../common"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const {deployments, getUnnamedAccounts} = hre; - const {deploy} = deployments; - - const [deployer] = await getUnnamedAccounts(); + const { deployments, getUnnamedAccounts } = hre; + const { deploy } = deployments; - if (!isDevNet(hre.network.name)) { - throw new Error('Interep not deployed on mainnet yet.') - } - const interepAddress = isDevNet(hre.network.name) ? (await deployments.get('InterepTest')).address : '0x0000000000000000000000000000000000000000'; - - await deploy('ValidGroupStorage', { - from: deployer, - log: true, - args: [interepAddress, getValidGroups()] - }); + const [deployer] = await getUnnamedAccounts(); + + if (!isDevNet(hre.network.name)) { + throw new Error("Interep not deployed on mainnet yet."); + } + const interepAddress = isDevNet(hre.network.name) + ? (await deployments.get("InterepTest")).address + : "0x0000000000000000000000000000000000000000"; + + await deploy("ValidGroupStorage", { + from: deployer, + log: true, + args: [interepAddress, getValidGroups()], + }); }; export default func; -func.tags = ['ValidGroupStorage']; -func.dependencies = ['InterepTest']; \ No newline at end of file +func.tags = ["ValidGroupStorage"]; +func.dependencies = ["InterepTest"]; diff --git a/deploy/004_deploy_rln.ts b/deploy/004_deploy_rln.ts index 52196e9..c321c6c 100644 --- a/deploy/004_deploy_rln.ts +++ b/deploy/004_deploy_rln.ts @@ -1,21 +1,28 @@ -import {HardhatRuntimeEnvironment} from 'hardhat/types'; -import {DeployFunction} from 'hardhat-deploy/types'; +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 { deployments, getUnnamedAccounts } = hre; + const { deploy } = deployments; - const poseidonHasherAddress = (await deployments.get('PoseidonHasher')).address; - const validGroupStorageAddress = (await deployments.get('ValidGroupStorage')).address; - - await deploy('RLN', { - from: deployer, - log: true, - args: [1000000000000000, 20, poseidonHasherAddress, validGroupStorageAddress] - }); + const [deployer] = await getUnnamedAccounts(); + + const poseidonHasherAddress = (await deployments.get("PoseidonHasher")) + .address; + const validGroupStorageAddress = (await deployments.get("ValidGroupStorage")) + .address; + + await deploy("RLN", { + from: deployer, + log: true, + args: [ + 1000000000000000, + 20, + poseidonHasherAddress, + validGroupStorageAddress, + ], + }); }; export default func; -func.tags = ['RLN']; -func.dependencies = ['PoseidonHasher', 'ValidGroupStorage']; \ No newline at end of file +func.tags = ["RLN"]; +func.dependencies = ["PoseidonHasher", "ValidGroupStorage"]; diff --git a/hardhat.config.ts b/hardhat.config.ts index 79b52e7..6fedb2b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -10,32 +10,35 @@ import "hardhat-gas-reporter"; import "solidity-coverage"; dotenv.config(); -const {GOERLI_URL,PRIVATE_KEY} = process.env; +const { GOERLI_URL, PRIVATE_KEY } = process.env; const getNetworkConfig = (): NetworksUserConfig | undefined => { - if (GOERLI_URL && PRIVATE_KEY) { - return { - goerli: { - url: GOERLI_URL, - accounts: [PRIVATE_KEY], - } - }; - } - return undefined; -} + if (GOERLI_URL && PRIVATE_KEY) { + return { + goerli: { + url: GOERLI_URL, + accounts: [PRIVATE_KEY], + }, + }; + } + 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.4", - }, { - version: "0.8.15" - }], + compilers: [ + { + version: "0.8.4", + }, + { + version: "0.8.15", + }, + ], }, - networks: getNetworkConfig() + networks: getNetworkConfig(), }; -export default config; \ No newline at end of file +export default config; diff --git a/package.json b/package.json index dffb553..11e7e02 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "deploy": "hardhat run scripts/deploy.ts --network", "deploy:goerli": "yarn deploy goerli", "deploy:localhost": "yarn deploy localhost", - "coverage": "hardhat coverage" + "coverage": "hardhat coverage", + "fmt": "prettier --write \"**/*.{js,ts}\"" }, "devDependencies": { "@interep/contracts": "0.6.0", @@ -24,6 +25,7 @@ "hardhat": "^2.9.9", "hardhat-deploy": "0.11.20", "hardhat-gas-reporter": "^1.0.8", + "prettier": "^2.8.0", "solidity-coverage": "^0.7.21", "ts-node": "^10.8.1", "typescript": "^4.7.4" @@ -31,4 +33,4 @@ "dependencies": { "dotenv": "^16.0.1" } -} +} \ No newline at end of file diff --git a/test/poseidon.ts b/test/poseidon.ts index bf2ae9f..1ef7146 100644 --- a/test/poseidon.ts +++ b/test/poseidon.ts @@ -8,10 +8,14 @@ describe("PoseidonHasher", () => { it("should hash correctly", async function () { const poseidonHasher = await ethers.getContract("PoseidonHasher"); - + // We test hashing for a random number - const hash = await poseidonHasher.hash("19014214495641488759237505126948346942972912379615652741039992445865937985820"); - - expect(hash._hex).to.eql("0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368"); + const hash = await poseidonHasher.hash( + "19014214495641488759237505126948346942972912379615652741039992445865937985820" + ); + + expect(hash._hex).to.eql( + "0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368" + ); }); }); diff --git a/test/rln.ts b/test/rln.ts index 10e55d0..83498b9 100644 --- a/test/rln.ts +++ b/test/rln.ts @@ -4,53 +4,66 @@ 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 idCommitment = + "0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368"; - - const registerTx = await rln['register(uint256)'](idCommitment, {value: price}); + const registerTx = await rln["register(uint256)"](idCommitment, { + value: price, + }); const txRegisterReceipt = await registerTx.wait(); - const pubkey = txRegisterReceipt.events[0].args.pubkey; + const pubkey = txRegisterReceipt.events[0].args.pubkey; // We ensure the registered id_commitment is the one we passed - expect(pubkey.toHexString() === idCommitment, "registered commitment doesn't match passed commitment"); + expect( + pubkey.toHexString() === idCommitment, + "registered commitment doesn't match passed commitment" + ); }); it("should withdraw membership", 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 idSecret = "0x2a09a9fd93c590c26b91effbb2499f07e8f7aa12e2b4940a3aed2411cb65e11c" - const idCommitment = "0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368" + const idSecret = + "0x2a09a9fd93c590c26b91effbb2499f07e8f7aa12e2b4940a3aed2411cb65e11c"; + const idCommitment = + "0x0c3ac305f6a4fe9bfeb3eba978bc876e2a99208b8b56c80160cfb54ba8f02368"; - - const registerTx = await rln['register(uint256)'](idCommitment, {value: price}); + const registerTx = await rln["register(uint256)"](idCommitment, { + value: price, + }); const txRegisterReceipt = await registerTx.wait(); - const treeIndex = txRegisterReceipt.events[0].args.index; + const treeIndex = txRegisterReceipt.events[0].args.index; // We withdraw our id_commitment - const receiverAddress = "0x000000000000000000000000000000000000dead"; - const withdrawTx = await rln.withdraw(idSecret, treeIndex, receiverAddress); - - const txWithdrawReceipt = await withdrawTx.wait(); - - const withdrawalPk = txWithdrawReceipt.events[0].args.pubkey; - const withdrawalTreeIndex = txWithdrawReceipt.events[0].args.index; - - // We ensure the registered id_commitment is the one we passed and that the index is the same - expect(withdrawalPk.toHexString() === idCommitment, "withdraw commitment doesn't match registered commitment"); - expect(withdrawalTreeIndex.toHexString() === treeIndex.toHexString(), "withdraw index doesn't match registered index"); - }) -}); \ No newline at end of file + const receiverAddress = "0x000000000000000000000000000000000000dead"; + const withdrawTx = await rln.withdraw(idSecret, treeIndex, receiverAddress); + + const txWithdrawReceipt = await withdrawTx.wait(); + + const withdrawalPk = txWithdrawReceipt.events[0].args.pubkey; + const withdrawalTreeIndex = txWithdrawReceipt.events[0].args.index; + + // We ensure the registered id_commitment is the one we passed and that the index is the same + expect( + withdrawalPk.toHexString() === idCommitment, + "withdraw commitment doesn't match registered commitment" + ); + expect( + withdrawalTreeIndex.toHexString() === treeIndex.toHexString(), + "withdraw index doesn't match registered index" + ); + }); +}); diff --git a/test/validGroupStorage.ts b/test/validGroupStorage.ts index 90cc8e7..f2f30ee 100644 --- a/test/validGroupStorage.ts +++ b/test/validGroupStorage.ts @@ -1,33 +1,42 @@ -import {expect} from "chai"; -import {ethers, deployments} from "hardhat"; -import {sToBytes32, createGroupId} from '../common'; - +import { expect } from "chai"; +import { ethers, deployments } from "hardhat"; +import { sToBytes32, createGroupId } from "../common"; describe("Valid Group Storage", () => { - beforeEach(async () => { - await deployments.fixture(['ValidGroupStorage']); - }) + beforeEach(async () => { + await deployments.fixture(["ValidGroupStorage"]); + }); - it('should not deploy if an invalid group is passed in constructor', async () => { - const interepTest = await ethers.getContract('InterepTest'); - const interepAddress = interepTest.address; - - const ValidGroupStorage = await ethers.getContractFactory("ValidGroupStorage"); - expect(ValidGroupStorage.deploy(interepAddress, [{ - provider: sToBytes32('github'), - name: sToBytes32('diamond'), - }])).to.be.revertedWith("[ValidGroupStorage] Invalid group"); - }) + it("should not deploy if an invalid group is passed in constructor", async () => { + const interepTest = await ethers.getContract("InterepTest"); + const interepAddress = interepTest.address; - it("should return true for valid group", async () => { - const validGroupStorage = await ethers.getContract('ValidGroupStorage'); - const valid = await validGroupStorage.isValidGroup(createGroupId('github', 'silver')); - expect(valid).to.be.true; - }); + const ValidGroupStorage = await ethers.getContractFactory( + "ValidGroupStorage" + ); + expect( + ValidGroupStorage.deploy(interepAddress, [ + { + provider: sToBytes32("github"), + name: sToBytes32("diamond"), + }, + ]) + ).to.be.revertedWith("[ValidGroupStorage] Invalid group"); + }); - it("should return false for invalid group", async () => { - const validGroupStorage = await ethers.getContract('ValidGroupStorage'); - const valid = await validGroupStorage.isValidGroup(createGroupId('github', 'bronze')); - expect(valid).to.be.false; - }); -}) \ No newline at end of file + it("should return true for valid group", async () => { + const validGroupStorage = await ethers.getContract("ValidGroupStorage"); + const valid = await validGroupStorage.isValidGroup( + createGroupId("github", "silver") + ); + expect(valid).to.be.true; + }); + + it("should return false for invalid group", async () => { + const validGroupStorage = await ethers.getContract("ValidGroupStorage"); + const valid = await validGroupStorage.isValidGroup( + createGroupId("github", "bronze") + ); + expect(valid).to.be.false; + }); +}); diff --git a/yarn.lock b/yarn.lock index 7e65a11..ed4f78a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6970,7 +6970,7 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prettier@^2.1.2: +prettier@^2.1.2, prettier@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.0.tgz#c7df58393c9ba77d6fba3921ae01faf994fb9dc9" integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==