Skip to content

Commit

Permalink
feat(contracts): add registry integration
Browse files Browse the repository at this point in the history
- [x] Add deploy poll task
- [x] Add init poll task
- [x] Link registry and poll
- [x] Add deploy poll registry method for MACI
  • Loading branch information
0xmad committed Aug 30, 2024
1 parent f0ff7c2 commit d0ba295
Show file tree
Hide file tree
Showing 17 changed files with 617 additions and 44 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/hardhat-tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ jobs:
run: |
cp ./deploy-config-example.json ./deploy-config.json
pnpm deploy:localhost
pnpm deploy-poll:localhost
pnpm initPoll:localhost --poll 0
working-directory: packages/contracts

- name: Stop Hardhat
Expand Down
4 changes: 4 additions & 0 deletions packages/contracts/contracts/interfaces/IPoll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ import { IOwnable } from "./IOwnable.sol";
interface IPoll is IPollBase, IOwnable {
/// @notice The initialization function.
function init() external;

/// @notice Set the poll registry.
/// @param registryAddress The registry address
function setRegistry(address registryAddress) external;
}
4 changes: 3 additions & 1 deletion packages/contracts/contracts/maci/MACI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SignUpGatekeeper } from "maci-contracts/contracts/gatekeepers/SignUpGat
import { ICommon } from "../interfaces/ICommon.sol";
import { IPoll } from "../interfaces/IPoll.sol";
import { IRegistryManager } from "../interfaces/IRegistryManager.sol";
import { EASRegistry } from "../registry/EASRegistry.sol";

/// @title MACI - Minimum Anti-Collusion Infrastructure
/// @notice A contract which allows users to sign up, and deploy new polls
Expand Down Expand Up @@ -51,10 +52,11 @@ contract MACI is Ownable, BaseMACI, ICommon {

/// @notice Initialize the poll by given poll id and transfer poll ownership to the caller.
/// @param pollId The poll id
function initPoll(uint256 pollId) public onlyOwner {
function initPoll(uint256 pollId, address registryAddress) public onlyOwner {
PollContracts memory pollAddresses = polls[pollId];
IPoll poll = IPoll(pollAddresses.poll);

poll.setRegistry(registryAddress);
poll.init();
poll.transferOwnership(msg.sender);
}
Expand Down
94 changes: 92 additions & 2 deletions packages/contracts/contracts/maci/Poll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,35 @@ pragma solidity ^0.8.20;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Poll as BasePoll } from "maci-contracts/contracts/Poll.sol";

import { ICommon } from "../interfaces/ICommon.sol";

/// @title Poll
/// @notice A Poll contract allows voters to submit encrypted messages
/// which can be either votes or key change messages.
/// @dev Do not deploy this directly. Use PollFactory.deploy() which performs some
/// checks on the Poll constructor arguments.
contract Poll is Ownable, BasePoll {
contract Poll is Ownable, BasePoll, ICommon {
/// @notice Poll specific registry
address public registry;

/// @notice The timestamp of the block at which the Poll was deployed
uint256 internal initTime;

/// @notice events
event SetRegistry(address indexed registry);

/// @notice custom errors
error RegistryAlreadyInitialized();
error RegistryNotInitialized();
error PollNotInitialized();

/// @notice Each MACI instance can have multiple Polls.
/// When a Poll is deployed, its voting period starts immediately.
/// @param duration The duration of the voting period, in seconds
/// @param treeDepths The depths of the merkle trees
/// @param coordinatorPubKey The coordinator's public key
/// @param extContracts The external contracts
/// @param emptyBallotRoot The empty ballot root
constructor(
uint256 duration,
TreeDepths memory treeDepths,
Expand All @@ -28,8 +45,81 @@ contract Poll is Ownable, BasePoll {
BasePoll(duration, treeDepths, coordinatorPubKey, extContracts, emptyBallotRoot)
{}

/// @notice Check if poll is initialized
modifier isPollInitialized() {
if (!isInit) {
revert PollNotInitialized();
}

_;
}

/// @notice Check if registry is initialized
modifier isRegistryInitialized() {
if (address(registry) == address(0)) {
revert RegistryNotInitialized();
}

_;
}

/// @notice Check if registry is valid and not initialized
/// @param registryAddress Registry address
modifier isRegistryNotInitialized(address registryAddress) {
if (registryAddress == address(0)) {
revert InvalidAddress();
}

if (address(registry) != address(0)) {
revert RegistryAlreadyInitialized();
}

_;
}

/// @notice A modifier that causes the function to revert if the voting period is
/// not over.
modifier isAfterVotingDeadline() override {
uint256 secondsPassed = block.timestamp - initTime;

if (secondsPassed <= duration) {
revert VotingPeriodNotOver();
}

_;
}

/// @notice A modifier that causes the function to revert if the voting period is
/// over
modifier isWithinVotingDeadline() override {
uint256 secondsPassed = block.timestamp - initTime;

if (secondsPassed >= duration) {
revert VotingPeriodOver();
}

_;
}

/// @notice Set poll registry.
/// @param registryAddress The registry address
function setRegistry(address registryAddress) public onlyOwner isRegistryNotInitialized(registryAddress) {
registry = registryAddress;

emit SetRegistry(registryAddress);
}

/// @notice The initialization function.
function init() public override onlyOwner {
function init() public override onlyOwner isRegistryInitialized {
initTime = block.timestamp;
super.init();
}

/// @inheritdoc BasePoll
function publishMessage(
Message memory message,
PubKey calldata encPubKey
) public override isPollInitialized isWithinVotingDeadline {
super.publishMessage(message, encPubKey);
}
}
14 changes: 14 additions & 0 deletions packages/contracts/deploy-config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0xC2679fBD37d54388Ce493F1DB75320D236e1815e"
},
"VkRegistry": {
Expand Down Expand Up @@ -101,6 +103,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0xaEF4103A04090071165F78D45D83A0C0782c2B2a"
},
"VkRegistry": {
Expand Down Expand Up @@ -167,6 +171,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0x4200000000000000000000000000000000000021"
},
"VkRegistry": {
Expand Down Expand Up @@ -233,6 +239,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0xC2679fBD37d54388Ce493F1DB75320D236e1815e"
},
"VkRegistry": {
Expand Down Expand Up @@ -299,6 +307,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0xC2679fBD37d54388Ce493F1DB75320D236e1815e"
},
"VkRegistry": {
Expand Down Expand Up @@ -365,6 +375,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0x4200000000000000000000000000000000000021"
},
"VkRegistry": {
Expand Down Expand Up @@ -436,6 +448,8 @@
"registryManager": "EASRegistryManager"
},
"EASRegistryManager": {
"maxRecipients": 25,
"metadataUrl": "url",
"easAddress": "0x4200000000000000000000000000000000000021"
},
"VkRegistry": {
Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "hardhat-artifactor";
import "hardhat-contract-sizer";
import "maci-contracts/tasks/deploy";
import "maci-contracts/tasks/runner/deployFull";
import "maci-contracts/tasks/runner/deployPoll";
import "maci-contracts/tasks/runner/verifyFull";
import "solidity-docgen";

Expand All @@ -13,6 +14,7 @@ import type { HardhatUserConfig } from "hardhat/config";
// Don't forget to import new tasks here
import "./tasks/deploy";
import { EChainId, ESupportedChains, getEtherscanApiKeys, getNetworkRpcUrls } from "./tasks/helpers/constants";
import "./tasks/runner/initPoll";

dotenv.config();

Expand Down
8 changes: 6 additions & 2 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@
"coverage": "BLOCK_GAS_LIMIT=1599511627775 hardhat coverage",
"test": "hardhat test --network hardhat",
"deploy": "hardhat deploy-full",
"deploy:localhost": "pnpm run deploy"
"initPoll": "hardhat initPoll",
"deploy-poll": "hardhat deploy-poll",
"deploy:localhost": "pnpm run deploy",
"deploy-poll:localhost": "pnpm run deploy-poll",
"initPoll:localhost": "pnpm run initPoll"
},
"dependencies": {
"@nomicfoundation/hardhat-ethers": "^3.0.6",
Expand All @@ -44,7 +48,7 @@
"ethers": "^6.13.2",
"hardhat": "^2.22.8",
"lowdb": "^1.0.0",
"maci-contracts": "0.0.0-ci.17a38c9",
"maci-contracts": "0.0.0-ci.a97f395",
"maci-core": "^2.2.0",
"maci-domainobjs": "^2.2.0",
"solidity-docgen": "^0.6.0-beta.36"
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/tasks/deploy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from "path";
/**
* The same as individual imports but doesn't require to add new import line every time
*/
["maci"].forEach((folder) => {
["maci", "poll"].forEach((folder) => {
const tasksPath = path.resolve(__dirname, folder);

if (fs.existsSync(tasksPath)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/tasks/deploy/maci/10-registryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ deployment.deployTask(EDeploySteps.RegistryManager, "Deploy registry manager").t

const registryManagerType =
deployment.getDeployConfigField<keyof typeof EContracts | null>(EContracts.MACI, "registryManager") ||
EContracts.RegistryManager;
EContracts.EASRegistryManager;

const registryManagerContractAddress = storage.getAddress(registryManagerType, hre.network.name);

Expand Down
Loading

0 comments on commit d0ba295

Please sign in to comment.