Skip to content

Commit

Permalink
feat: implement contract registries
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 committed Oct 3, 2024
1 parent d78fb04 commit 9bb935c
Show file tree
Hide file tree
Showing 61 changed files with 1,645 additions and 663 deletions.
3 changes: 3 additions & 0 deletions packages/contracts/contracts/interfaces/IRegistryManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface IRegistryManager {
address indexed registry,
RequestType indexed requestType,
bytes32 indexed recipient,
uint256 recipientIndex,
uint256 index,
address payout,
string metadataUrl
Expand All @@ -47,6 +48,7 @@ interface IRegistryManager {
address indexed registry,
RequestType indexed requestType,
bytes32 indexed recipient,
uint256 recipientIndex,
uint256 index,
address payout,
string metadataUrl
Expand All @@ -55,6 +57,7 @@ interface IRegistryManager {
address indexed registry,
RequestType indexed requestType,
bytes32 indexed recipient,
uint256 recipientIndex,
uint256 index,
address payout,
string metadataUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,20 @@ contract RegistryManager is Ownable, IRegistryManager, ICommon {
/// @inheritdoc IRegistryManager
function process(Request memory request) public virtual override isValidRequest(request) {
request.status = Status.Pending;
requests[requestCount] = request;
uint256 index = requestCount;

unchecked {
requestCount++;
}

requests[index] = request;

emit RequestSent(
request.registry,
request.requestType,
request.recipient.id,
request.index,
index,
request.recipient.recipient,
request.recipient.metadataUrl
);
Expand All @@ -85,6 +88,7 @@ contract RegistryManager is Ownable, IRegistryManager, ICommon {
request.requestType,
request.recipient.id,
request.index,
index,
request.recipient.recipient,
request.recipient.metadataUrl
);
Expand All @@ -108,6 +112,7 @@ contract RegistryManager is Ownable, IRegistryManager, ICommon {
request.requestType,
request.recipient.id,
request.index,
index,
request.recipient.recipient,
request.recipient.metadataUrl
);
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 @@ -7,6 +7,8 @@ import "maci-contracts/tasks/deploy";
import "maci-contracts/tasks/runner/deployFull";
import "maci-contracts/tasks/runner/deployPoll";
import "maci-contracts/tasks/runner/verifyFull";
import "maci-contracts/tasks/runner/merge";
import "maci-contracts/tasks/runner/prove";
import "solidity-docgen";

import type { HardhatUserConfig } from "hardhat/config";
Expand Down
8 changes: 7 additions & 1 deletion packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@
"deploy:optimism-sepolia": "pnpm run deploy --network optimism_sepolia",
"deploy-poll:optimism-sepolia": "pnpm run deploy-poll --network optimism_sepolia",
"initPoll:optimism-sepolia": "pnpm run initPoll --network optimism_sepolia",
"verify:optimism-sepolia": "pnpm run verify --network optimism_sepolia"
"verify:optimism-sepolia": "pnpm run verify --network optimism_sepolia",
"merge": "hardhat merge",
"merge:localhost": "pnpm run merge",
"merge:optimism-sepolia": "pnpm run merge --network optimism_sepolia",
"prove": "hardhat prove",
"prove:localhost": "pnpm run prove",
"prove:optimism-sepolia": "pnpm run prove --network optimism_sepolia"
},
"dependencies": {
"@nomicfoundation/hardhat-ethers": "^3.0.8",
Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/ts/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { ERegistryManagerRequestType, ERegistryManagerRequestStatus } from "./constants";

export * from "../typechain-types";
1 change: 1 addition & 0 deletions packages/interface/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"lucide-react": "^0.316.0",
"maci-cli": "^2.4.0",
"maci-domainobjs": "^2.4.0",
"maci-platform-contracts": "workspace:*",
"next": "^14.1.0",
"next-auth": "^4.24.5",
"next-themes": "^0.2.1",
Expand Down
11 changes: 9 additions & 2 deletions packages/interface/src/components/AddedProjects.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { zeroAddress } from "viem";
import { useAccount } from "wagmi";

import { useBallot } from "~/contexts/Ballot";
import { useMaci } from "~/contexts/Maci";
import { useProjectCount } from "~/features/projects/hooks/useProjects";

export const AddedProjects = (): JSX.Element => {
const { ballot } = useBallot();
const { pollData } = useMaci();
const { chain } = useAccount();
const { data: projectCount } = useProjectCount({ registryAddress: pollData?.registry ?? zeroAddress, chain: chain! });

const allocations = ballot.votes;
const { data: projectCount } = useProjectCount();

return (
<div className="border-b border-gray-200 py-2">
Expand All @@ -20,7 +27,7 @@ export const AddedProjects = (): JSX.Element => {
</span>

<span className="text-gray-300">
<b>{projectCount?.count}</b>
<b>{projectCount?.count.toString()}</b>
</span>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/interface/src/components/EmptyState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type PropsWithChildren } from "react";
import { Heading } from "./ui/Heading";

export const EmptyState = ({ title, children = null }: PropsWithChildren<{ title: string }>): JSX.Element => (
<div className="flex flex-col items-center justify-center rounded border p-8">
<div className="m-2 flex flex-col items-center justify-center rounded border p-8">
<Heading as="h3" className="mt-0" size="lg">
{title}
</Heading>
Expand Down
13 changes: 7 additions & 6 deletions packages/interface/src/contexts/Ballot.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { createContext, useContext, useState, useEffect, useMemo, useCallback } from "react";
import { useAccount } from "wagmi";
import { useMaci } from "./Maci";

import type { BallotContextType, BallotProviderProps } from "./types";
import type { Ballot, Vote } from "~/features/ballot/types";

import { useMaci } from "./Maci";

export const BallotContext = createContext<BallotContextType | undefined>(undefined);

// the default ballot is an empty ballot
const defaultBallot = { votes: [], published: false, edited: false };

export const BallotProvider: React.FC<BallotProviderProps> = ({ children }: BallotProviderProps) => {
Expand All @@ -28,7 +28,8 @@ export const BallotProvider: React.FC<BallotProviderProps> = ({ children }: Ball
[pollData],
);

const ballotContains = useCallback((id: string) => ballot.votes.find((v) => v.projectId === id), [ballot]);
// check if the ballot contains a specific project based on its index
const ballotContains = useCallback((index: number) => ballot.votes.find((v) => v.projectIndex === index), [ballot]);

const toObject = useCallback(
(key: string, arr: object[] = []) => arr.reduce((acc, x) => ({ ...acc, [x[key as keyof typeof acc]]: x }), {}),
Expand All @@ -55,8 +56,8 @@ export const BallotProvider: React.FC<BallotProviderProps> = ({ children }: Ball

// remove certain project from the ballot
const removeFromBallot = useCallback(
(projectId: string) => {
const votes = ballot.votes.filter((v) => v.projectId !== projectId);
(projectIndex: number) => {
const votes = ballot.votes.filter((v) => v.projectIndex !== projectIndex);

setBallot({ ...ballot, votes });
},
Expand Down Expand Up @@ -86,7 +87,7 @@ export const BallotProvider: React.FC<BallotProviderProps> = ({ children }: Ball
setBallot({ ...ballot, published: true, edited: false });
}, [ballot, setBallot]);

/// Read existing ballot in localStorage
// Read existing ballot in localStorage
useEffect(() => {
const savedBallot = JSON.parse(
localStorage.getItem("ballot") ?? JSON.stringify(defaultBallot),
Expand Down
52 changes: 7 additions & 45 deletions packages/interface/src/contexts/Maci.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
import { type StandardMerkleTreeData } from "@openzeppelin/merkle-tree/dist/standard";
import { type ZKEdDSAEventTicketPCD } from "@pcd/zk-eddsa-event-ticket-pcd/ZKEdDSAEventTicketPCD";
import { Identity } from "@semaphore-protocol/core";
import { isAfter } from "date-fns";
import { type Signer, BrowserProvider, AbiCoder } from "ethers";
import { type Signer, AbiCoder } from "ethers";
import {
signup,
isRegisteredUser,
publishBatch,
type TallyData,
type IGetPollData,
getPoll,
genKeyPair,
GatekeeperTrait,
getGatekeeperTrait,
Expand All @@ -29,7 +26,7 @@ import { getSemaphoreProof } from "~/utils/semaphore";

import type { IVoteArgs, MaciContextType, MaciProviderProps } from "./types";
import type { PCD } from "@pcd/pcd-types";
import type { EIP1193Provider } from "viem";
import type { IPollData } from "~/utils/fetchPoll";
import type { Attestation } from "~/utils/types";

export const MaciContext = createContext<MaciContextType | undefined>(undefined);
Expand All @@ -48,7 +45,7 @@ export const MaciProvider: React.FC<MaciProviderProps> = ({ children }: MaciProv
const [initialVoiceCredits, setInitialVoiceCredits] = useState<number>(0);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string>();
const [pollData, setPollData] = useState<IGetPollData>();
const [pollData, setPollData] = useState<IPollData>();
const [tallyData, setTallyData] = useState<TallyData>();
const [treeData, setTreeData] = useState<StandardMerkleTreeData<string[]>>();

Expand Down Expand Up @@ -251,6 +248,7 @@ export const MaciProvider: React.FC<MaciProviderProps> = ({ children }: MaciProv
setSemaphoreIdentity(newSemaphoreIdentity);
}, [address, signatureMessage, signMessageAsync, setMaciPrivKey, setMaciPubKey, setSemaphoreIdentity]);

// callback to be called from external component to store the zupass proof
const storeZupassProof = useCallback(
(proof: PCD) => {
setZupassProof(proof);
Expand All @@ -262,7 +260,7 @@ export const MaciProvider: React.FC<MaciProviderProps> = ({ children }: MaciProv
const votingEndsAt = useMemo(
() =>
pollData && pollData.duration !== 0
? new Date(Number(pollData.deployTime) * 1000 + Number(pollData.duration) * 1000)
? new Date(Number(pollData.initTime) * 1000 + Number(pollData.duration) * 1000)
: config.resultsAt,
[pollData?.deployTime, pollData?.duration],
);
Expand Down Expand Up @@ -410,15 +408,14 @@ export const MaciProvider: React.FC<MaciProviderProps> = ({ children }: MaciProv

/// check the poll data and tally data
useEffect(() => {
setIsLoading(true);

// if we have the subgraph url then it means we can get the poll data through there
if (config.maciSubgraphUrl) {
if (!poll.data) {
setIsLoading(false);
return;
}

setIsLoading(true);

const { isMerged, id } = poll.data;

setPollData(poll.data);
Expand All @@ -433,41 +430,6 @@ export const MaciProvider: React.FC<MaciProviderProps> = ({ children }: MaciProv
}

setIsLoading(false);
} else {
if (!window.ethereum) {
setIsLoading(false);
return;
}

const provider = new BrowserProvider(window.ethereum as unknown as EIP1193Provider, {
chainId: config.network.id,
name: config.network.name,
});

getPoll({
maciAddress: config.maciAddress!,
provider,
})
.then((data) => {
setPollData(data);
return data;
})
.then(async (data) => {
if (!data.isMerged || (votingEndsAt && isAfter(votingEndsAt, new Date()))) {
return undefined;
}

return fetch(`${config.tallyUrl}/tally-${data.id}.json`)
.then((res) => res.json() as Promise<TallyData>)
.then((res) => {
setTallyData(res);
})
.catch(() => undefined);
})
.catch(console.error)
.finally(() => {
setIsLoading(false);
});
}
}, [signer, votingEndsAt, setIsLoading, setTallyData, setPollData, poll.data]);

Expand Down
9 changes: 5 additions & 4 deletions packages/interface/src/contexts/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { type StandardMerkleTreeData } from "@openzeppelin/merkle-tree/dist/standard";
import { type TallyData, type IGetPollData, type GatekeeperTrait } from "maci-cli/sdk";
import { type TallyData, type GatekeeperTrait } from "maci-cli/sdk";
import { type ReactNode } from "react";

import type { PCD } from "@pcd/pcd-types";
import type { Ballot, Vote } from "~/features/ballot/types";
import type { IPollData } from "~/utils/fetchPoll";

export interface IVoteArgs {
voteOptionIndex: bigint;
Expand All @@ -19,7 +20,7 @@ export interface MaciContextType {
isRegistered?: boolean;
pollId?: string;
error?: string;
pollData?: IGetPollData;
pollData?: IPollData;
tallyData?: TallyData;
maciPubKey?: string;
gatekeeperTrait?: GatekeeperTrait;
Expand All @@ -41,9 +42,9 @@ export interface BallotContextType {
ballot: Ballot;
isLoading: boolean;
addToBallot: (votes: Vote[], pollId?: string) => void;
removeFromBallot: (projectId: string) => void;
removeFromBallot: (projectIndex: number) => void;
deleteBallot: () => void;
ballotContains: (id: string) => Vote | undefined;
ballotContains: (index: number) => Vote | undefined;
sumBallot: (votes?: Vote[]) => number;
publishBallot: () => void;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Transaction } from "@ethereum-attestation-service/eas-sdk";
import { useRouter } from "next/router";
import { useState, useCallback } from "react";
import { useLocalStorage } from "react-use";
Expand Down Expand Up @@ -52,13 +51,13 @@ export const ApplicationForm = (): JSX.Element => {
}, [step, setStep]);

const create = useCreateApplication({
onSuccess: (data: Transaction<string[]>) => {
onSuccess: (id: bigint) => {
clearDraft();
router.push(`/applications/confirmation?txHash=${data.tx.hash}`);
router.push(`/applications/confirmation?id=${id.toString()}`);
},
onError: (err: { reason?: string; data?: { message: string } }) =>
onError: (err: { message: string }) =>
toast.error("Application create error", {
description: err.reason ?? err.data?.message,
description: err.message,
}),
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Attestation } from "~/utils/types";
import type { IRequest } from "~/utils/types";

import { SelectAllButton } from "./SelectAllButton";

interface IApplicationHeaderProps {
applications?: Attestation[];
applications?: IRequest[];
}

export const ApplicationHeader = ({ applications = [] }: IApplicationHeaderProps): JSX.Element => (
Expand Down
Loading

0 comments on commit 9bb935c

Please sign in to comment.