Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use gatekeeper per poll #1961

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 30 additions & 8 deletions packages/cli/ts/commands/deployPoll.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MACI__factory as MACIFactory, EMode } from "maci-contracts";
import { MACI__factory as MACIFactory, EMode, deployFreeForAllSignUpGatekeeper } from "maci-contracts";
import { PubKey } from "maci-domainobjs";

import {
Expand Down Expand Up @@ -26,6 +26,7 @@ export const deployPoll = async ({
coordinatorPubkey,
maciAddress,
vkRegistryAddress,
gatekeeperAddress,
signer,
quiet = true,
useQuadraticVoting = false,
Expand All @@ -49,6 +50,18 @@ export const deployPoll = async ({

const maci = maciAddress || maciContractAddress;

const maciContract = MACIFactory.connect(maci, signer);
const pollId = await maciContract.nextPollId();

// check if we have a signupGatekeeper already deployed or passed as arg
let signupGatekeeperContractAddress =
gatekeeperAddress || (await readContractAddress(`SignUpGatekeeper-${pollId.toString()}`, network?.name));

if (!signupGatekeeperContractAddress) {
const contract = await deployFreeForAllSignUpGatekeeper(signer, true);
signupGatekeeperContractAddress = await contract.getAddress();
ctrlc03 marked this conversation as resolved.
Show resolved Hide resolved
}

// required arg -> poll duration
if (pollDuration <= 0) {
logError("Duration cannot be <= 0");
Expand Down Expand Up @@ -83,8 +96,6 @@ export const deployPoll = async ({
// get the verifier contract
const verifierContractAddress = await readContractAddress("Verifier", network?.name);

const maciContract = MACIFactory.connect(maci, signer);

// deploy the poll
let pollAddr = "";
let messageProcessorContractAddress = "";
Expand All @@ -103,6 +114,7 @@ export const deployPoll = async ({
verifierContractAddress,
vkRegistry,
useQuadraticVoting ? EMode.QV : EMode.NON_QV,
signupGatekeeperContractAddress,
{ gasLimit: 10000000 },
);

Expand Down Expand Up @@ -130,8 +142,8 @@ export const deployPoll = async ({
}

// eslint-disable-next-line no-underscore-dangle
const pollId = log.args._pollId;
const pollContracts = await maciContract.getPoll(pollId);
const eventPollId = log.args._pollId;
const pollContracts = await maciContract.getPoll(eventPollId);
pollAddr = pollContracts.poll;
messageProcessorContractAddress = pollContracts.messageProcessor;
tallyContractAddress = pollContracts.tally;
Expand All @@ -142,9 +154,18 @@ export const deployPoll = async ({
logGreen(quiet, info(`Tally contract: ${tallyContractAddress}`));

// store the address
await storeContractAddress(`MessageProcessor-${pollId.toString()}`, messageProcessorContractAddress, network?.name);
await storeContractAddress(`Tally-${pollId.toString()}`, tallyContractAddress, network?.name);
await storeContractAddress(`Poll-${pollId.toString()}`, pollAddr, network?.name);
await storeContractAddress(
`SignUpGatekeeper-${eventPollId.toString()}`,
signupGatekeeperContractAddress,
network?.name,
);
await storeContractAddress(
`MessageProcessor-${eventPollId.toString()}`,
messageProcessorContractAddress,
network?.name,
);
await storeContractAddress(`Tally-${eventPollId.toString()}`, tallyContractAddress, network?.name);
await storeContractAddress(`Poll-${eventPollId.toString()}`, pollAddr, network?.name);
} catch (error) {
logError((error as Error).message);
}
Expand All @@ -154,5 +175,6 @@ export const deployPoll = async ({
messageProcessor: messageProcessorContractAddress,
tally: tallyContractAddress,
poll: pollAddr,
signupGatekeeper: signupGatekeeperContractAddress,
};
};
6 changes: 5 additions & 1 deletion packages/cli/ts/commands/joinPoll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import fs from "fs";

import type { IJoinPollArgs, IJoinedUserArgs, IParsePollJoinEventsArgs, IJoinPollData } from "../utils";

import { contractExists, logError, logYellow, info, logGreen, success, BLOCKS_STEP } from "../utils";
import { contractExists, logError, logYellow, info, logGreen, success, BLOCKS_STEP, DEFAULT_SG_DATA } from "../utils";
import { banner } from "../utils/banner";

/**
Expand Down Expand Up @@ -195,6 +195,7 @@ export const joinPoll = async ({
rapidsnark,
pollWitgen,
pollWasm,
sgDataArg,
quiet = true,
}: IJoinPollArgs): Promise<IJoinPollData> => {
banner(quiet);
Expand Down Expand Up @@ -332,6 +333,8 @@ export const joinPoll = async ({
let pollStateIndex = "";
let receipt: ContractTransactionReceipt | null = null;

const sgData = sgDataArg || DEFAULT_SG_DATA;

try {
// generate the proof for this batch
const proof = await generateAndVerifyProof(
Expand All @@ -351,6 +354,7 @@ export const joinPoll = async ({
loadedCreditBalance!,
currentStateRootIndex,
proof,
sgData,
);
receipt = await tx.wait();
logYellow(quiet, info(`Transaction hash: ${receipt!.hash}`));
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ program
.description("join the poll")
.requiredOption("-sk, --priv-key <privKey>", "the private key")
.option("-i, --state-index <stateIndex>", "the user's state index", BigInt)
.requiredOption("-s, --sg-data <sgData>", "the signup gateway data")
.requiredOption("-esk, --poll-priv-key <pollPrivKey>", "the user ephemeral private key for the poll")
.option(
"-nv, --new-voice-credit-balance <newVoiceCreditBalance>",
Expand Down Expand Up @@ -265,6 +266,7 @@ program
useWasm: cmdObj.wasm,
rapidsnark: cmdObj.rapidsnark,
pollWitgen: cmdObj.pollWitnessgen,
sgDataArg: cmdObj.sgData,
});
} catch (error) {
program.error((error as Error).message, { exitCode: 1 });
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/ts/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface PollContracts {
poll: string;
messageProcessor: string;
tally: string;
signupGatekeeper: string;
}

/**
Expand Down Expand Up @@ -318,6 +319,11 @@ export interface DeployPollArgs {
* Whether to use quadratic voting or not
*/
useQuadraticVoting?: boolean;

/**
* The address of the gatekeeper contract
*/
gatekeeperAddress?: string;
}

/**
Expand Down Expand Up @@ -447,6 +453,11 @@ export interface IJoinPollArgs {
* Poll private key for the poll
*/
pollPrivKey: string;

/**
* The signup gatekeeper data
*/
sgDataArg?: string;
}

/**
Expand Down
7 changes: 5 additions & 2 deletions packages/contracts/contracts/MACI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { IMessageProcessorFactory } from "./interfaces/IMPFactory.sol";
import { ITallyFactory } from "./interfaces/ITallyFactory.sol";
import { IVerifier } from "./interfaces/IVerifier.sol";
import { IVkRegistry } from "./interfaces/IVkRegistry.sol";
import { ISignUpGatekeeper } from "./interfaces/ISignUpGatekeeper.sol";
import { InitialVoiceCreditProxy } from "./initialVoiceCreditProxy/InitialVoiceCreditProxy.sol";
import { SignUpGatekeeper } from "./gatekeepers/SignUpGatekeeper.sol";
import { IMACI } from "./interfaces/IMACI.sol";
Expand Down Expand Up @@ -187,7 +188,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities {
PubKey memory _coordinatorPubKey,
address _verifier,
address _vkRegistry,
Mode _mode
Mode _mode,
Dismissed Show dismissed Hide dismissed
address _gatekeeper
Dismissed Show dismissed Hide dismissed
) public virtual {
// cache the poll to a local variable so we can increment it
uint256 pollId = nextPollId;
Expand All @@ -208,7 +210,8 @@ contract MACI is IMACI, DomainObjs, Params, Utilities {
ExtContracts memory extContracts = ExtContracts({
maci: IMACI(address(this)),
verifier: IVerifier(_verifier),
vkRegistry: IVkRegistry(_vkRegistry)
vkRegistry: IVkRegistry(_vkRegistry),
gatekeeper: ISignUpGatekeeper(_gatekeeper)
});

address p = pollFactory.deploy(
Expand Down
18 changes: 11 additions & 7 deletions packages/contracts/contracts/Poll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SnarkCommon } from "./crypto/SnarkCommon.sol";
import { LazyIMTData, InternalLazyIMT } from "./trees/LazyIMT.sol";
import { IMACI } from "./interfaces/IMACI.sol";
import { IPoll } from "./interfaces/IPoll.sol";
import { ISignUpGatekeeper } from "./interfaces/ISignUpGatekeeper.sol";
import { Utilities } from "./utilities/Utilities.sol";
import { CurveBabyJubJub } from "./crypto/BabyJubJub.sol";

Expand Down Expand Up @@ -284,28 +285,31 @@ contract Poll is Params, Utilities, SnarkCommon, IPoll {
PubKey calldata _pubKey,
uint256 _newVoiceCreditBalance,
uint256 _stateRootIndex,
uint256[8] calldata _proof
uint256[8] calldata _proof,
Dismissed Show dismissed Hide dismissed
bytes memory _signUpGatekeeperData
Dismissed Show dismissed Hide dismissed
) public virtual isWithinVotingDeadline {
// Whether the user has already joined
if (pollNullifier[_nullifier]) {
revert UserAlreadyJoined();
}

// Set nullifier for user's private key
pollNullifier[_nullifier] = true;

// Verify user's proof
if (!verifyPollProof(_nullifier, _newVoiceCreditBalance, _stateRootIndex, _pubKey, _proof)) {
revert InvalidPollProof();
}

// Check if the user is eligible to join the poll
extContracts.gatekeeper.register(msg.sender, _signUpGatekeeperData);

// Store user in the pollStateTree
uint256 timestamp = block.timestamp;
uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, _newVoiceCreditBalance, timestamp));
uint256 stateLeaf = hashStateLeaf(StateLeaf(_pubKey, _newVoiceCreditBalance, block.timestamp));
InternalLazyIMT._insert(pollStateTree, stateLeaf);

// Set nullifier for user's private key
pollNullifier[_nullifier] = true;

uint256 pollStateIndex = pollStateTree.numberOfLeaves - 1;
emit PollJoined(_pubKey.x, _pubKey.y, _newVoiceCreditBalance, timestamp, _nullifier, pollStateIndex);
emit PollJoined(_pubKey.x, _pubKey.y, _newVoiceCreditBalance, block.timestamp, _nullifier, pollStateIndex);
}

/// @notice Verify the proof for Poll
Expand Down
3 changes: 2 additions & 1 deletion packages/contracts/contracts/interfaces/IPoll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ interface IPoll {
DomainObjs.PubKey calldata _pubKey,
uint256 _newVoiceCreditBalance,
uint256 _stateRootIndex,
uint256[8] calldata _proof
uint256[8] calldata _proof,
bytes memory _signUpGatekeeperData
) external;

/// @notice The number of messages which have been processed and the number of signups
Expand Down
11 changes: 11 additions & 0 deletions packages/contracts/contracts/interfaces/ISignUpGatekeeper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

/// @title ISignUpGatekeeper
/// @notice SignUpGatekeeper interface
interface ISignUpGatekeeper {
/// @notice Register a user
/// @param _user User address
/// @param _data Data to register
function register(address _user, bytes memory _data) external;
}
2 changes: 2 additions & 0 deletions packages/contracts/contracts/utilities/Params.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import { IMACI } from "../interfaces/IMACI.sol";
import { IVerifier } from "../interfaces/IVerifier.sol";
import { IVkRegistry } from "../interfaces/IVkRegistry.sol";
import { ISignUpGatekeeper } from "../interfaces/ISignUpGatekeeper.sol";

/// @title Params
/// @notice This contracts contains a number of structures
Expand All @@ -24,5 +25,6 @@ contract Params {
IMACI maci;
IVerifier verifier;
IVkRegistry vkRegistry;
ISignUpGatekeeper gatekeeper;
}
}
33 changes: 22 additions & 11 deletions packages/contracts/deploy-config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"scroll_sepolia": {
Expand Down Expand Up @@ -133,7 +134,8 @@
"Poll": {
"pollDuration": 10800,
"coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"optimism": {
Expand Down Expand Up @@ -202,7 +204,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"arbitrum_sepolia": {
Expand Down Expand Up @@ -271,7 +274,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"localhost": {
Expand Down Expand Up @@ -340,7 +344,8 @@
"Poll": {
"pollDuration": 30,
"coordinatorPubkey": "macipk.29add77d27341c4cdfc2fb623175ecfd6527a286e3e7ded785d9fd7afbbdf399",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"base_sepolia": {
Expand Down Expand Up @@ -409,7 +414,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"optimism_sepolia": {
Expand Down Expand Up @@ -483,7 +489,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.9a59264310d95cfd8eb7083aebeba221b5c26e77427f12b7c0f50bc1cc35e621",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"gnosis_chiado": {
Expand Down Expand Up @@ -557,7 +564,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"gnosis": {
Expand Down Expand Up @@ -631,7 +639,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a",
"useQuadraticVoting": false
"useQuadraticVoting": false,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"polygon_amoy": {
Expand Down Expand Up @@ -705,7 +714,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a",
"useQuadraticVoting": true
"useQuadraticVoting": true,
"gatekeeper": "FreeForAllGatekeeper"
}
},
"polygon": {
Expand Down Expand Up @@ -779,7 +789,8 @@
"Poll": {
"pollDuration": 3600,
"coordinatorPubkey": "macipk.0a1ce79a43fa676ee3d2882c79d9164a24d4a22bb6190e3d8fa25d97bffc069a",
"useQuadraticVoting": true
"useQuadraticVoting": true,
"gatekeeper": "FreeForAllGatekeeper"
}
}
}
Loading
Loading