feat(rln): store valid group ids from interep
This commit is contained in:
parent
db3beff91a
commit
0b287c40c2
|
@ -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 {}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
})
|
Loading…
Reference in New Issue