feat(rln): store valid group ids from interep

This commit is contained in:
rymnc 2022-11-24 12:09:44 +05:30
parent db3beff91a
commit 0b287c40c2
No known key found for this signature in database
GPG Key ID: C740033EE3F41EBD
6 changed files with 292 additions and 2 deletions

60
contracts/InterepTest.sol Normal file
View File

@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@interep/contracts/IInterep.sol";
import "@semaphore-protocol/contracts/interfaces/IVerifier.sol";
import "@semaphore-protocol/contracts/base/SemaphoreCore.sol";
import "@semaphore-protocol/contracts/base/SemaphoreConstants.sol";
contract InterepTest is IInterep, SemaphoreCore {
mapping(uint256 => Group) public groups;
/// @dev mimics https://github.com/interep-project/contracts/blob/main/contracts/Interep.sol but ignores the verification mechanism
constructor() {}
/// @dev See {IInterep-updateGroups}.
function updateGroups(Group[] calldata _groups) external override {
for (uint8 i = 0; i < _groups.length; i++) {
uint256 groupId = uint256(
keccak256(
abi.encodePacked(_groups[i].provider, _groups[i].name)
)
) % SNARK_SCALAR_FIELD;
_updateGroup(groupId, _groups[i]);
}
}
/// @dev See {IInterep-getRoot}.
function getRoot(uint256 groupId) public view override returns (uint256) {
return groups[groupId].root;
}
/// @dev See {IInterep-getDepth}.
function getDepth(uint256 groupId) public view override returns (uint8) {
return groups[groupId].depth;
}
/// @dev Updates an Interep group.
/// @param groupId: Id of the group.
/// @param group: Group data.
function _updateGroup(uint256 groupId, Group calldata group) private {
groups[groupId] = group;
emit GroupUpdated(
groupId,
group.provider,
group.name,
group.root,
group.depth
);
}
function verifyProof(
uint256 groupId,
bytes32 signal,
uint256 nullifierHash,
uint256 externalNullifier,
uint256[8] calldata proof
) external override {}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@interep/contracts/Interep.sol";
contract ValidGroupStorage {
mapping(uint256 => bool) public validGroups;
Interep public interep;
struct Group {
bytes32 provider;
bytes32 name;
}
constructor(address _interep, Group[] memory _groups) {
interep = Interep(_interep);
for (uint8 i = 0; i < _groups.length; i++) {
uint256 groupId = uint256(
keccak256(
abi.encodePacked(_groups[i].provider, _groups[i].name)
)
) % SNARK_SCALAR_FIELD;
(bytes32 provider, bytes32 name, , ) = interep.groups(groupId);
if (provider == _groups[i].provider && name == _groups[i].name) {
validGroups[groupId] = true;
} else {
revert("[ValidGroupStorage] Invalid group");
}
}
}
function isValidGroup(uint256 _groupId) public view returns (bool) {
return validGroups[_groupId];
}
}

View File

@ -23,7 +23,13 @@ task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
// Go to https://hardhat.org/config/ to learn more
const config: HardhatUserConfig = {
solidity: "0.8.15",
solidity: {
compilers: [{
version: "0.8.4",
}, {
version: "0.8.15"
}],
},
networks: {
goerli: {
url: GOERLI_URL,

100
package-lock.json generated
View File

@ -9,9 +9,11 @@
"dotenv": "^16.0.1"
},
"devDependencies": {
"@interep/contracts": "0.6.0",
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@semaphore-protocol/contracts": "2.6.1",
"@types/mocha": "^9.1.1",
"chai": "^4.3.6",
"ethereum-waffle": "^3.4.4",
@ -23,6 +25,22 @@
"typescript": "^4.7.4"
}
},
"node_modules/@appliedzkp/semaphore-contracts": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@appliedzkp/semaphore-contracts/-/semaphore-contracts-0.8.1.tgz",
"integrity": "sha512-pIaTPgsxbNEXBcoGjt3qjh/+Uhl/tlfQSDR7261GYRGWdgO0T3/F/ewv/8U2WtlnnUmy83LQ1Y50+Iys9X8E6Q==",
"dev": true,
"dependencies": {
"@openzeppelin/contracts": "^4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "^0.3.1"
}
},
"node_modules/@appliedzkp/semaphore-contracts/node_modules/@zk-kit/incremental-merkle-tree.sol": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@zk-kit/incremental-merkle-tree.sol/-/incremental-merkle-tree.sol-0.3.1.tgz",
"integrity": "sha512-85rZpeSJGeR0yEiIbJwWrZgA68ovc62XiOHcMvAZmJtISsYMVHqzN6w4ax9Ke6bE70sj5V0OSPZ89vgJZ0zxgg==",
"dev": true
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -1178,6 +1196,16 @@
"@ethersproject/strings": "^5.6.1"
}
},
"node_modules/@interep/contracts": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@interep/contracts/-/contracts-0.6.0.tgz",
"integrity": "sha512-Tot6yy6dHCJJsM+2b7sBMN03TEu1sPW2Qzymu2ItbDXh3MmrbUaWblwZ+U5x/UE3ZpeSfP+ZFzGO1d1b35kJug==",
"dev": true,
"dependencies": {
"@appliedzkp/semaphore-contracts": "^0.8.0",
"@openzeppelin/contracts": "^4.5.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz",
@ -1355,6 +1383,12 @@
"hardhat": "^2.0.0"
}
},
"node_modules/@openzeppelin/contracts": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.7.3.tgz",
"integrity": "sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw==",
"dev": true
},
"node_modules/@resolver-engine/core": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.3.3.tgz",
@ -1481,6 +1515,16 @@
"@scure/base": "~1.1.0"
}
},
"node_modules/@semaphore-protocol/contracts": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@semaphore-protocol/contracts/-/contracts-2.6.1.tgz",
"integrity": "sha512-USEw3eZT4im7n8PpsoYyEEKiabmEtUCLMKIuZkMdjSA8k3jg25Y7WR07XFWqKur0OEb4n1nCX3+/ROTWKWSlJA==",
"dev": true,
"dependencies": {
"@openzeppelin/contracts": "4.7.3",
"@zk-kit/incremental-merkle-tree.sol": "1.3.1"
}
},
"node_modules/@sentry/core": {
"version": "5.30.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz",
@ -1937,6 +1981,12 @@
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
"dev": true
},
"node_modules/@zk-kit/incremental-merkle-tree.sol": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@zk-kit/incremental-merkle-tree.sol/-/incremental-merkle-tree.sol-1.3.1.tgz",
"integrity": "sha512-KdGPoEooSX5MJH7oBE7MCRt/Aej+6n7U6v81w9fIzorSbykNuKH5lMbjkDAsis5xhp2qBC+y1V0xYBA2SNMt8A==",
"dev": true
},
"node_modules/abbrev": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
@ -20662,6 +20712,24 @@
}
},
"dependencies": {
"@appliedzkp/semaphore-contracts": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@appliedzkp/semaphore-contracts/-/semaphore-contracts-0.8.1.tgz",
"integrity": "sha512-pIaTPgsxbNEXBcoGjt3qjh/+Uhl/tlfQSDR7261GYRGWdgO0T3/F/ewv/8U2WtlnnUmy83LQ1Y50+Iys9X8E6Q==",
"dev": true,
"requires": {
"@openzeppelin/contracts": "^4.4.2",
"@zk-kit/incremental-merkle-tree.sol": "^0.3.1"
},
"dependencies": {
"@zk-kit/incremental-merkle-tree.sol": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@zk-kit/incremental-merkle-tree.sol/-/incremental-merkle-tree.sol-0.3.1.tgz",
"integrity": "sha512-85rZpeSJGeR0yEiIbJwWrZgA68ovc62XiOHcMvAZmJtISsYMVHqzN6w4ax9Ke6bE70sj5V0OSPZ89vgJZ0zxgg==",
"dev": true
}
}
},
"@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@ -21450,6 +21518,16 @@
"@ethersproject/strings": "^5.6.1"
}
},
"@interep/contracts": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@interep/contracts/-/contracts-0.6.0.tgz",
"integrity": "sha512-Tot6yy6dHCJJsM+2b7sBMN03TEu1sPW2Qzymu2ItbDXh3MmrbUaWblwZ+U5x/UE3ZpeSfP+ZFzGO1d1b35kJug==",
"dev": true,
"requires": {
"@appliedzkp/semaphore-contracts": "^0.8.0",
"@openzeppelin/contracts": "^4.5.0"
}
},
"@jridgewell/resolve-uri": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz",
@ -21590,6 +21668,12 @@
"@types/web3": "1.0.19"
}
},
"@openzeppelin/contracts": {
"version": "4.7.3",
"resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.7.3.tgz",
"integrity": "sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw==",
"dev": true
},
"@resolver-engine/core": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@resolver-engine/core/-/core-0.3.3.tgz",
@ -21706,6 +21790,16 @@
"@scure/base": "~1.1.0"
}
},
"@semaphore-protocol/contracts": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@semaphore-protocol/contracts/-/contracts-2.6.1.tgz",
"integrity": "sha512-USEw3eZT4im7n8PpsoYyEEKiabmEtUCLMKIuZkMdjSA8k3jg25Y7WR07XFWqKur0OEb4n1nCX3+/ROTWKWSlJA==",
"dev": true,
"requires": {
"@openzeppelin/contracts": "4.7.3",
"@zk-kit/incremental-merkle-tree.sol": "1.3.1"
}
},
"@sentry/core": {
"version": "5.30.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz",
@ -22134,6 +22228,12 @@
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
"dev": true
},
"@zk-kit/incremental-merkle-tree.sol": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@zk-kit/incremental-merkle-tree.sol/-/incremental-merkle-tree.sol-1.3.1.tgz",
"integrity": "sha512-KdGPoEooSX5MJH7oBE7MCRt/Aej+6n7U6v81w9fIzorSbykNuKH5lMbjkDAsis5xhp2qBC+y1V0xYBA2SNMt8A==",
"dev": true
},
"abbrev": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",

View File

@ -1,6 +1,8 @@
{
"name": "hardhat-project",
"devDependencies": {
"@interep/contracts": "0.6.0",
"@semaphore-protocol/contracts": "2.6.1",
"@nomiclabs/hardhat-ethers": "^2.0.6",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
@ -17,4 +19,4 @@
"dependencies": {
"dotenv": "^16.0.1"
}
}
}

86
test/validGroupStorage.ts Normal file
View File

@ -0,0 +1,86 @@
import {expect} from "chai";
import { Contract } from "ethers";
import {ethers} from "hardhat";
const sToBytes32 = (str: string): string => {
return ethers.utils.formatBytes32String(str);
}
const SNARK_SCALAR_FIELD = BigInt(
"21888242871839275222246405745257275088548364400416034343698204186575808495617"
)
const createGroupId = (provider: string, name: string): bigint => {
const providerBytes = sToBytes32(provider);
const nameBytes = sToBytes32(name);
return BigInt(ethers.utils.solidityKeccak256(["bytes32", "bytes32"], [providerBytes, nameBytes])) % SNARK_SCALAR_FIELD
}
const providers = ['github', 'twitter', 'reddit'];
const tiers = ['bronze', 'silver', 'gold'];
const scaffoldInterep = async () => {
// Deploy interep
const InterepTest = await ethers.getContractFactory("InterepTest");
const interepTest = await InterepTest.deploy();
await interepTest.deployed();
const interepAddress = interepTest.address;
// add all combinations of providers and tiers into an array
const groups = providers.flatMap(provider => tiers.map(tier => {
return {
provider: sToBytes32(provider),
name: sToBytes32(tier),
root: 1,
depth: 10,
}
}));
// insert groups into interep membership contract
const groupInsertionTx = await interepTest.updateGroups(groups);
await groupInsertionTx.wait();
return {interepTest, groups}
}
const scaffold = async () => {
const {interepTest, groups} = await scaffoldInterep();
const interepAddress = interepTest.address;
// create valid group storage contract for rln
const ValidGroupStorage = await ethers.getContractFactory("ValidGroupStorage");
const filteredGroups = groups
.filter(group => group.name !== sToBytes32('bronze'));
const validGroupStorage = await ValidGroupStorage.deploy(interepAddress, filteredGroups);
await validGroupStorage.deployed();
expect(validGroupStorage.address).to.not.equal(0);
return validGroupStorage
}
describe("Valid Group Storage", () => {
let validGroupStorage: Contract;
beforeEach(async () => {
validGroupStorage = await scaffold();
})
it('should not deploy if an invalid group is passed in constructor', async () => {
const {interepTest} = await scaffoldInterep();
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 return true for valid group", async () => {
const valid = await validGroupStorage.isValidGroup(createGroupId('github', 'silver'));
expect(valid).to.be.true;
});
it("should return false for invalid group", async () => {
const valid = await validGroupStorage.isValidGroup(createGroupId('github', 'bronze'));
expect(valid).to.be.false;
});
})