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 1, 2024
1 parent d78fb04 commit 70a9eb5
Show file tree
Hide file tree
Showing 50 changed files with 1,527 additions and 521 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/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
49 changes: 5 additions & 44 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 @@ -410,15 +407,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 +429,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
5 changes: 3 additions & 2 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 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
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,42 @@ import { Skeleton } from "~/components/ui/Skeleton";
import { ProjectAvatar } from "~/features/projects/components/ProjectAvatar";
import { useMetadata } from "~/hooks/useMetadata";
import { formatDate } from "~/utils/time";
import { IRecipient } from "~/utils/types";

import type { Application } from "~/features/applications/types";
import type { Attestation } from "~/utils/types";

export interface IApplicationItemProps extends Attestation {
export interface IApplicationItemProps {
index: string;
recipient: IRecipient;
isApproved?: boolean;
isLoading?: boolean;
}

export const ApplicationItem = ({
id,
index,
recipient,
name,
metadataPtr,
time,
isApproved = false,
isLoading = false,
}: IApplicationItemProps): JSX.Element => {
const metadata = useMetadata<Application>(metadataPtr);
const metadata = useMetadata<Application>(recipient.metadataUrl);

const form = useFormContext();

const { fundingSources = [], profileImageUrl } = metadata.data ?? {};

return (
<Link href={`/projects/${id}`} target="_blank">
<Link href={`/projects/${recipient.id}`} target="_blank">
<div className="dark:hover:bg-lighterBlack flex cursor-pointer items-center gap-2 py-4 hover:bg-blue-50">
<label className="flex flex-1 cursor-pointer justify-center p-2">
<Checkbox disabled={isApproved} value={id} {...form.register(`selected`)} type="checkbox" />
<Checkbox disabled={isApproved} value={index} {...form.register(`selected`)} type="checkbox" />
</label>

<div className="flex flex-[8] items-center gap-4">
<ProjectAvatar isLoading={isLoading} profileId={recipient} size="sm" url={profileImageUrl} />
<ProjectAvatar isLoading={isLoading} size="sm" url={profileImageUrl} />

<div className="flex flex-col">
<Skeleton className="mb-1 min-h-5 min-w-24" isLoading={isLoading}>
<span className="uppercase">{name}</span>
<span className="uppercase">{metadata.data?.name}</span>
</Skeleton>

<div className="text-sm text-gray-400">
Expand All @@ -57,7 +56,7 @@ export const ApplicationItem = ({
<ClockIcon className="size-3" />

<Skeleton className="mb-1 min-h-5 min-w-24" isLoading={isLoading}>
{formatDate(time * 1000)}
{metadata.data?.submittedAt ? formatDate(metadata.data.submittedAt) : "N/A"}
</Skeleton>
</div>

Expand Down
Loading

0 comments on commit 70a9eb5

Please sign in to comment.