mirror of
https://github.com/yashgo0018/maci-wrapper.git
synced 2026-05-04 03:00:44 -04:00
496
packages/nextjs/abi/AccQueue.ts
Normal file
496
packages/nextjs/abi/AccQueue.ts
Normal file
@@ -0,0 +1,496 @@
|
||||
export default [
|
||||
{
|
||||
inputs: [],
|
||||
name: "DepthCannotBeZero",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_depth",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "max",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "DepthTooLarge",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_depth",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "min",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "DepthTooSmall",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "InvalidHashLength",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_index",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "InvalidIndex",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "InvalidLevel",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "NothingToMerge",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "SubDepthCannotBeZero",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "SubTreesAlreadyMerged",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "SubTreesNotMerged",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_subDepth",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "max",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "SubdepthTooLarge",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "previousOwner",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "newOwner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "OwnershipTransferred",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "MAX_DEPTH",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "calcMinHeight",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "depth",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_leaf",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "enqueue",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "leafIndex",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "fill",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_depth",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "getMainRoot",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "mainRoot",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "getSmallSRTroot",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "smallSubTreeRoot",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "getSrIndices",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "next",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "current",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_index",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "getSubRoot",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "subRoot",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256[2]",
|
||||
name: "array",
|
||||
type: "uint256[2]",
|
||||
},
|
||||
],
|
||||
name: "hash2",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256[3]",
|
||||
name: "array",
|
||||
type: "uint256[3]",
|
||||
},
|
||||
],
|
||||
name: "hash3",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256[4]",
|
||||
name: "array",
|
||||
type: "uint256[4]",
|
||||
},
|
||||
],
|
||||
name: "hash4",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256[5]",
|
||||
name: "array",
|
||||
type: "uint256[5]",
|
||||
},
|
||||
],
|
||||
name: "hash5",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "left",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "right",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "hashLeftRight",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_level",
|
||||
type: "uint256",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_leaf",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "hashLevelLeaf",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_hash",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_subRoot",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "insertSubTree",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_depth",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "merge",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "root",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "_numSrQueueOps",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "mergeSubRoots",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "numLeaves",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "owner",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "renounceOwnership",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256[]",
|
||||
name: "array",
|
||||
type: "uint256[]",
|
||||
},
|
||||
],
|
||||
name: "sha256Hash",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "result",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
stateMutability: "pure",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "subTreesMerged",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "newOwner",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
name: "transferOwnership",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "treeMerged",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
] as const;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Dialog } from "@headlessui/react";
|
||||
import { LuCross } from "react-icons/lu";
|
||||
import { MdEdit } from "react-icons/md";
|
||||
@@ -6,7 +6,15 @@ import { RxCross2 } from "react-icons/rx";
|
||||
import Modal from "~~/components/Modal";
|
||||
import { useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
|
||||
|
||||
export default function Example({ show, setOpen }: { show: boolean; setOpen: (value: boolean) => void }) {
|
||||
export default function Example({
|
||||
show,
|
||||
setOpen,
|
||||
refetchPolls,
|
||||
}: {
|
||||
show: boolean;
|
||||
setOpen: (value: boolean) => void;
|
||||
refetchPolls: () => void;
|
||||
}) {
|
||||
const [pollData, setPollData] = useState({ title: "Dummy Title", options: [""] });
|
||||
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
|
||||
|
||||
@@ -41,19 +49,14 @@ export default function Example({ show, setOpen }: { show: boolean; setOpen: (va
|
||||
const { writeAsync, data, isLoading } = useScaffoldContractWrite({
|
||||
contractName: "PollManager",
|
||||
functionName: "createPoll",
|
||||
args: [pollData?.title, pollData?.options || [], "", 300n],
|
||||
args: [pollData?.title, pollData?.options || [], "", 60n],
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
|
||||
useEffect(() => {
|
||||
// setIsLoading(isLoading);
|
||||
}, [isLoading]);
|
||||
|
||||
async function onSubmit() {
|
||||
console.log("A");
|
||||
try {
|
||||
await writeAsync();
|
||||
refetchPolls();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
126
packages/nextjs/app/admin/_components/PollStatusModal.tsx
Normal file
126
packages/nextjs/app/admin/_components/PollStatusModal.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { Dialog } from "@headlessui/react";
|
||||
import { useContractRead } from "wagmi";
|
||||
import AccQueueAbi from "~~/abi/AccQueue";
|
||||
import PollAbi from "~~/abi/Poll";
|
||||
import Modal from "~~/components/Modal";
|
||||
import { useScaffoldContractRead } from "~~/hooks/scaffold-eth";
|
||||
import { Poll } from "~~/types/poll";
|
||||
import { mergeSignups } from "~~/utils/mergeSignups";
|
||||
|
||||
const stepNames = ["Merge SignUps", "Merge Main Roots", "Compute Main Root"];
|
||||
|
||||
export default function PollStatusModal({
|
||||
poll,
|
||||
show,
|
||||
setOpen,
|
||||
}: {
|
||||
show: boolean;
|
||||
setOpen: (value: boolean) => void;
|
||||
poll: Poll | undefined;
|
||||
}) {
|
||||
// console.log("stateAq", stateAq, subTreesMerged);
|
||||
|
||||
const { data: stateAq } = useScaffoldContractRead({ contractName: "MACI", functionName: "stateAq" });
|
||||
const { data: stateTreeDepth, refetch: refetchStateTreeDepth } = useScaffoldContractRead({
|
||||
contractName: "MACI",
|
||||
functionName: "stateTreeDepth",
|
||||
});
|
||||
const { data: mainRoot1, refetch: refetchMainRoot1 } = useContractRead({
|
||||
abi: AccQueueAbi,
|
||||
address: stateAq,
|
||||
functionName: "getMainRoot",
|
||||
args: stateTreeDepth ? [BigInt(stateTreeDepth)] : undefined,
|
||||
});
|
||||
|
||||
const { data: treeDepths, refetch: refetchTreeDepths } = useContractRead({
|
||||
abi: PollAbi,
|
||||
address: poll?.pollContracts.poll,
|
||||
functionName: "treeDepths",
|
||||
});
|
||||
const [, , messageTreeDepth] = treeDepths || [undefined, undefined, undefined, undefined];
|
||||
console.log(messageTreeDepth);
|
||||
const { data: extContracts, refetch: refetchExtContracts } = useContractRead({
|
||||
abi: PollAbi,
|
||||
address: poll?.pollContracts.poll,
|
||||
functionName: "extContracts",
|
||||
});
|
||||
const [, messageAq] = extContracts || [undefined, undefined, undefined];
|
||||
const { data: mainRoot2, refetch: refetchMainRoot2 } = useContractRead({
|
||||
abi: AccQueueAbi,
|
||||
address: messageAq,
|
||||
functionName: "getMainRoot",
|
||||
args: messageTreeDepth ? [BigInt(messageTreeDepth)] : undefined,
|
||||
});
|
||||
|
||||
// check if the message AQ has been fully merged
|
||||
// const messageTreeDepth = Number((await pollContract.treeDepths()).messageTreeDepth);
|
||||
|
||||
// check if the main root was not already computed
|
||||
// const mainRoot = (await accQueueContract.getMainRoot(messageTreeDepth.toString())).toString();
|
||||
|
||||
console.log(mainRoot1, mainRoot2);
|
||||
|
||||
function refetch() {
|
||||
refetchStateTreeDepth();
|
||||
refetchTreeDepths();
|
||||
refetchExtContracts();
|
||||
refetchMainRoot1();
|
||||
refetchMainRoot2();
|
||||
}
|
||||
|
||||
let step = 1;
|
||||
if (mainRoot1) {
|
||||
step = 2;
|
||||
if (mainRoot2) {
|
||||
step = 3;
|
||||
}
|
||||
}
|
||||
|
||||
async function mergeSignupStep() {
|
||||
if (!poll?.pollContracts.poll) return;
|
||||
|
||||
await mergeSignups({ pollContractAddress: poll?.pollContracts.poll });
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal show={show} setOpen={setOpen}>
|
||||
<div className="mt-3 text-center sm:mt-5 mb-6">
|
||||
<Dialog.Title as="h3" className="font-bold leading-6 text-2xl text-neutral-content">
|
||||
Required Actions
|
||||
</Dialog.Title>
|
||||
</div>
|
||||
<div className=" ">
|
||||
<div className="text-center text-lg">
|
||||
Step {step} - {stepNames[step - 1]}
|
||||
</div>
|
||||
{step === 1 && (
|
||||
<div className="text-center">
|
||||
<div className="text-sm">Merge the signup subtrees of the accumulator queue</div>
|
||||
<div className="mockup-code bg-primary text-primary-content text-left mt-5">
|
||||
<pre data-prefix="$">
|
||||
<code>node build/ts/index.js mergeSignups -o {poll?.maciPollId.toString()}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex w-full justify-center rounded-md bg-primary text-primary-content px-3 py-2 font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:col-start-2"
|
||||
onClick={refetch}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:col-start-1 sm:mt-0"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -3,11 +3,13 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { redirect } from "next/navigation";
|
||||
import CreatePollModal from "./_components/CreatePollModal";
|
||||
import PollStatusModal from "./_components/PollStatusModal";
|
||||
import { useAccount } from "wagmi";
|
||||
import Paginator from "~~/components/Paginator";
|
||||
import { useScaffoldContractRead } from "~~/hooks/scaffold-eth";
|
||||
import { useFetchPolls } from "~~/hooks/useFetchPolls";
|
||||
import { useTotalPages } from "~~/hooks/useTotalPages";
|
||||
import { Poll, PollStatus } from "~~/types/poll";
|
||||
|
||||
export default function AdminPage() {
|
||||
const { address } = useAccount();
|
||||
@@ -15,8 +17,9 @@ export default function AdminPage() {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const { data: admin } = useScaffoldContractRead({ contractName: "MACI", functionName: "owner" });
|
||||
const [limit] = useState(10);
|
||||
const { totalPolls, polls } = useFetchPolls(currentPage, limit);
|
||||
const { totalPolls, polls, refetch: refetchPolls } = useFetchPolls(currentPage, limit);
|
||||
const totalPages = useTotalPages(totalPolls, limit);
|
||||
const [selectedPollForStatusModal, setSelectedPollForStatusModal] = useState<Poll>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!admin || !address) return;
|
||||
@@ -54,7 +57,18 @@ export default function AdminPage() {
|
||||
<td>{poll.name}</td>
|
||||
<td>{new Date(Number(poll.startTime) * 1000).toLocaleString()}</td>
|
||||
<td>{new Date(Number(poll.endTime) * 1000).toLocaleString()}</td>
|
||||
<td>Poll Open</td>
|
||||
<td>
|
||||
{poll.status == PollStatus.CLOSED ? (
|
||||
<>
|
||||
{poll.status}{" "}
|
||||
<button className=" text-accent underline" onClick={() => setSelectedPollForStatusModal(poll)}>
|
||||
(Required Actions)
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
poll.status
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -67,7 +81,13 @@ export default function AdminPage() {
|
||||
<div>No polls found</div>
|
||||
)}
|
||||
|
||||
<CreatePollModal setOpen={setOpenCreatePollModal} show={openCreatePollModal} />
|
||||
<CreatePollModal refetchPolls={refetchPolls} show={openCreatePollModal} setOpen={setOpenCreatePollModal} />
|
||||
|
||||
<PollStatusModal
|
||||
poll={selectedPollForStatusModal}
|
||||
setOpen={() => setSelectedPollForStatusModal(undefined)}
|
||||
show={Boolean(selectedPollForStatusModal)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
7
packages/nextjs/app/api/polls/[id]/route.ts
Normal file
7
packages/nextjs/app/api/polls/[id]/route.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { coordinator } from "~~/utils/coordinator";
|
||||
|
||||
export const POST = async (req: NextRequest, { params: { id } }: { params: { id: string } }) => {
|
||||
coordinator.closePoll(parseInt(id));
|
||||
return NextResponse.json({ message: "Hello, World!" });
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import { useParams } from "next/navigation";
|
||||
import { genRandomSalt } from "@se-2/hardhat/maci-ts/crypto";
|
||||
import { Keypair, Message, PCommand, PubKey } from "@se-2/hardhat/maci-ts/domainobjs";
|
||||
import { useContractRead, useContractWrite } from "wagmi";
|
||||
import PollAbi from "~~/abi/Poll.json";
|
||||
import PollAbi from "~~/abi/Poll";
|
||||
import VoteCard from "~~/components/card/VoteCard";
|
||||
import { useAuthContext } from "~~/contexts/AuthContext";
|
||||
import { useAuthUserOnly } from "~~/hooks/useAuthUserOnly";
|
||||
@@ -18,7 +18,7 @@ export default function PollDetail() {
|
||||
|
||||
useAuthUserOnly({});
|
||||
|
||||
const { keypair } = useAuthContext();
|
||||
const { keypair, stateIndex } = useAuthContext();
|
||||
|
||||
const [clickedIndex, setClickedIndex] = useState<number | null>(null);
|
||||
const handleCardClick = (index: number) => {
|
||||
@@ -27,6 +27,7 @@ export default function PollDetail() {
|
||||
|
||||
const castVote = async () => {
|
||||
console.log("Voting for candidate", clickedIndex);
|
||||
console.log("A", message?.message.asContractParam(), message?.encKeyPair.pubKey.asContractParam());
|
||||
// navigate to the home page
|
||||
try {
|
||||
// setLoaderMessage("Casting the vote, please wait...");
|
||||
@@ -43,14 +44,12 @@ export default function PollDetail() {
|
||||
abi: PollAbi,
|
||||
address: poll?.pollContracts.poll,
|
||||
functionName: "maxValues",
|
||||
args: [],
|
||||
});
|
||||
|
||||
const { data: coordinatorPubKeyResult } = useContractRead({
|
||||
abi: PollAbi,
|
||||
address: poll?.pollContracts.poll,
|
||||
functionName: "coordinatorPubKey",
|
||||
args: [],
|
||||
});
|
||||
|
||||
const [message, setMessage] = useState<{ message: Message; encKeyPair: Keypair }>();
|
||||
@@ -61,7 +60,7 @@ export default function PollDetail() {
|
||||
abi: PollAbi,
|
||||
address: poll?.pollContracts.poll,
|
||||
functionName: "publishMessage",
|
||||
args: [message?.message.asContractParam(), message?.encKeyPair.pubKey.asContractParam()],
|
||||
args: message ? [message.message.asContractParam(), message.encKeyPair.pubKey.asContractParam()] : undefined,
|
||||
});
|
||||
|
||||
const [coordinatorPubKey, setCoordinatorPubKey] = useState<PubKey>();
|
||||
@@ -77,14 +76,15 @@ export default function PollDetail() {
|
||||
]);
|
||||
|
||||
setCoordinatorPubKey(coordinatorPubKey_);
|
||||
}, [`coordinatorPubKeyResult`]);
|
||||
}, [coordinatorPubKeyResult]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!clickedIndex || !coordinatorPubKey || !keypair) {
|
||||
if (!clickedIndex || !coordinatorPubKey || !keypair || !stateIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const command: PCommand = new PCommand(
|
||||
1n, // stateindex
|
||||
stateIndex, // stateindex
|
||||
keypair.pubKey, // userMaciPubKey
|
||||
BigInt(clickedIndex),
|
||||
1n,
|
||||
@@ -100,7 +100,7 @@ export default function PollDetail() {
|
||||
const message = command.encrypt(signature, Keypair.genEcdhSharedKey(encKeyPair.privKey, coordinatorPubKey));
|
||||
|
||||
setMessage({ message, encKeyPair });
|
||||
}, [id, clickedIndex, coordinatorPubKey, keypair]);
|
||||
}, [id, clickedIndex, coordinatorPubKey, keypair, stateIndex]);
|
||||
|
||||
console.log(maxValues && (maxValues as any)[1]);
|
||||
console.log(coordinatorPubKeyResult);
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function Modal({
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-neutral px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
|
||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-neutral text-neutral-content px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
|
||||
{children}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,74 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useScaffoldContractRead } from "./scaffold-eth";
|
||||
import { Poll, PollStatus, RawPoll } from "~~/types/poll";
|
||||
|
||||
export function getPollStatus(poll: RawPoll) {
|
||||
const now = Math.round(new Date().getTime() / 1000);
|
||||
|
||||
if (poll.startTime > BigInt(now)) {
|
||||
return PollStatus.NOT_STARTED;
|
||||
}
|
||||
|
||||
if (poll.endTime > BigInt(now)) {
|
||||
return PollStatus.OPEN;
|
||||
}
|
||||
|
||||
if (!poll.tallyJsonCID) {
|
||||
return PollStatus.CLOSED;
|
||||
}
|
||||
|
||||
return PollStatus.RESULT_COMPUTED;
|
||||
}
|
||||
|
||||
export const useFetchPolls = (currentPage = 1, limit = 10, reversed = true) => {
|
||||
const { data: totalPolls } = useScaffoldContractRead({
|
||||
const [polls, setPolls] = useState<Poll[]>();
|
||||
const { data: totalPolls, refetch: refetchTotalPolls } = useScaffoldContractRead({
|
||||
contractName: "PollManager",
|
||||
functionName: "totalPolls",
|
||||
});
|
||||
|
||||
const { data: polls } = useScaffoldContractRead({
|
||||
const { data: rawPolls, refetch: refetchPolls } = useScaffoldContractRead({
|
||||
contractName: "PollManager",
|
||||
functionName: "fetchPolls",
|
||||
args: [BigInt(currentPage), BigInt(limit), reversed],
|
||||
});
|
||||
|
||||
return { totalPolls: Number(totalPolls || 0n), polls };
|
||||
const [lastTimer, setLastTimer] = useState<NodeJS.Timer>();
|
||||
|
||||
useEffect(() => {
|
||||
if (lastTimer) {
|
||||
clearInterval(lastTimer);
|
||||
}
|
||||
|
||||
if (!rawPolls) {
|
||||
setPolls([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const _polls: Poll[] = [];
|
||||
|
||||
for (const rawPoll of rawPolls) {
|
||||
_polls.push({
|
||||
...rawPoll,
|
||||
status: getPollStatus(rawPoll),
|
||||
});
|
||||
}
|
||||
|
||||
setPolls(_polls);
|
||||
}, 1000);
|
||||
|
||||
setLastTimer(interval);
|
||||
|
||||
() => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [rawPolls]);
|
||||
|
||||
function refetch() {
|
||||
refetchTotalPolls();
|
||||
refetchPolls();
|
||||
}
|
||||
|
||||
return { totalPolls: Number(totalPolls || 0n), polls, refetch };
|
||||
};
|
||||
|
||||
0
packages/nextjs/hooks/useMergeSignups.tsx
Normal file
0
packages/nextjs/hooks/useMergeSignups.tsx
Normal file
43
packages/nextjs/types/poll.ts
Normal file
43
packages/nextjs/types/poll.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export enum PollStatus {
|
||||
NOT_STARTED = "Not Started",
|
||||
OPEN = "Open",
|
||||
CLOSED = "Closed",
|
||||
RESULT_COMPUTED = "Result Computed",
|
||||
}
|
||||
|
||||
export interface RawPoll {
|
||||
id: bigint;
|
||||
maciPollId: bigint;
|
||||
name: string;
|
||||
encodedOptions: `0x${string}`;
|
||||
ipfsHash: string;
|
||||
pollContracts: {
|
||||
poll: string;
|
||||
messageProcessor: string;
|
||||
tally: string;
|
||||
};
|
||||
startTime: bigint;
|
||||
endTime: bigint;
|
||||
numOfOptions: bigint;
|
||||
options: readonly string[];
|
||||
tallyJsonCID: string;
|
||||
}
|
||||
|
||||
export interface Poll {
|
||||
id: bigint;
|
||||
maciPollId: bigint;
|
||||
name: string;
|
||||
encodedOptions: `0x${string}`;
|
||||
ipfsHash: string;
|
||||
pollContracts: {
|
||||
poll: string;
|
||||
messageProcessor: string;
|
||||
tally: string;
|
||||
};
|
||||
startTime: bigint;
|
||||
endTime: bigint;
|
||||
numOfOptions: bigint;
|
||||
options: readonly string[];
|
||||
tallyJsonCID: string;
|
||||
status: PollStatus;
|
||||
}
|
||||
66
packages/nextjs/utils/coordinator.ts
Normal file
66
packages/nextjs/utils/coordinator.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { genMACIState } from "./genMaciState";
|
||||
import { mergeMessages } from "./mergeMessages";
|
||||
import { mergeSignups } from "./mergeSignups";
|
||||
import { Keypair, PrivKey } from "@se-2/hardhat/maci-ts/domainobjs";
|
||||
import { Address, PublicClient, createPublicClient, getContract, http } from "viem";
|
||||
import deployedContracts from "~~/contracts/deployedContracts";
|
||||
import scaffoldConfig from "~~/scaffold.config";
|
||||
|
||||
class Coordinator {
|
||||
closing: Record<number, boolean> = {};
|
||||
targetNetwork = scaffoldConfig.targetNetworks[0];
|
||||
publicClient: PublicClient;
|
||||
|
||||
constructor() {
|
||||
this.publicClient = createPublicClient({ chain: this.targetNetwork, transport: http() });
|
||||
}
|
||||
|
||||
async closePoll(pollId: number) {
|
||||
if (this.closing[pollId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { address: pollManagerAddress, abi: pollManagerAbi } = deployedContracts[this.targetNetwork.id].PollManager;
|
||||
|
||||
const pollManager = getContract({
|
||||
abi: pollManagerAbi,
|
||||
address: pollManagerAddress,
|
||||
publicClient: this.publicClient,
|
||||
});
|
||||
|
||||
if (Number(await pollManager.read.totalPolls()) < pollId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const poll = await pollManager.read.fetchPoll([BigInt(pollId)]);
|
||||
|
||||
if (new Date(Number(poll.endTime) * 1000) > new Date()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// console.log(poll);
|
||||
|
||||
// TODO: check if the poll is already closed
|
||||
|
||||
// const provider = this.publicClient.provider();
|
||||
const coordinatorPrivateKey = new PrivKey(process.env.COORDINATOR_PRIVATE_KEY as string);
|
||||
|
||||
console.log(process.env.COORDINATOR_PRIVATE_KEY);
|
||||
|
||||
const coordinatorKeypair = new Keypair(coordinatorPrivateKey);
|
||||
|
||||
await mergeSignups({ pollContractAddress: poll.pollContracts.poll as Address });
|
||||
await mergeMessages({ pollContractAddress: poll.pollContracts.poll as Address });
|
||||
|
||||
await genMACIState({ pollContractAddress: poll.pollContracts.poll as Address, coordinatorKeypair });
|
||||
|
||||
// console.log(poll);
|
||||
|
||||
this.closing[pollId] = true;
|
||||
|
||||
// Close the poll
|
||||
console.log(`Closing poll ${pollId}`);
|
||||
}
|
||||
}
|
||||
|
||||
export const coordinator = new Coordinator();
|
||||
0
packages/nextjs/utils/genLocalState.ts
Normal file
0
packages/nextjs/utils/genLocalState.ts
Normal file
658
packages/nextjs/utils/genMaciState.ts
Normal file
658
packages/nextjs/utils/genMaciState.ts
Normal file
@@ -0,0 +1,658 @@
|
||||
import { MaciState, STATE_TREE_ARITY } from "@se-2/hardhat/maci-ts/core";
|
||||
import { Keypair, Message, PubKey } from "@se-2/hardhat/maci-ts/domainobjs";
|
||||
import assert from "assert";
|
||||
import { Address, createPublicClient, getContract, http } from "viem";
|
||||
import PollAbi from "~~/abi/Poll";
|
||||
import deployedContracts from "~~/contracts/deployedContracts";
|
||||
import scaffoldConfig from "~~/scaffold.config";
|
||||
|
||||
export interface Action {
|
||||
type: string;
|
||||
data: Partial<{
|
||||
pubKey: PubKey;
|
||||
encPubKey: PubKey;
|
||||
message: Message;
|
||||
voiceCreditBalance: number;
|
||||
timestamp: number;
|
||||
stateIndex: number;
|
||||
numSrQueueOps: number;
|
||||
pollId: bigint;
|
||||
pollAddr: string;
|
||||
stateRoot: bigint;
|
||||
messageRoot: bigint;
|
||||
}>;
|
||||
blockNumber: bigint;
|
||||
transactionIndex: number;
|
||||
}
|
||||
|
||||
export function sortActions(actions: Action[]): Action[] {
|
||||
return actions.slice().sort((a, b) => {
|
||||
if (a.blockNumber > b.blockNumber) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.blockNumber < b.blockNumber) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.transactionIndex > b.transactionIndex) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a.transactionIndex < b.transactionIndex) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
export async function genMACIState({
|
||||
pollContractAddress,
|
||||
coordinatorKeypair,
|
||||
}: {
|
||||
pollContractAddress: Address;
|
||||
coordinatorKeypair: Keypair;
|
||||
}) {
|
||||
const chain = scaffoldConfig.targetNetworks[0];
|
||||
const publicClient = createPublicClient({ chain, transport: http() });
|
||||
const { address: MaciAddress, abi: MaciAbi, deploymentBlockNumber } = deployedContracts[chain.id].MACI;
|
||||
|
||||
console.log(deploymentBlockNumber);
|
||||
|
||||
const maciContract = getContract({ abi: MaciAbi, address: MaciAddress, publicClient });
|
||||
const stateTreeDepth = await maciContract.read.stateTreeDepth();
|
||||
|
||||
const maciState = new MaciState(stateTreeDepth);
|
||||
|
||||
assert(stateTreeDepth === maciState.stateTreeDepth);
|
||||
|
||||
const lastBlock = await publicClient.getBlockNumber();
|
||||
const startBlock = BigInt(0);
|
||||
const blocksPerRequest = 50;
|
||||
|
||||
const deployPollLogs = await maciContract.getEvents.DeployPoll({}, { fromBlock: startBlock, toBlock: lastBlock });
|
||||
const signUpLogs = await maciContract.getEvents.SignUp({}, { fromBlock: startBlock, toBlock: lastBlock });
|
||||
|
||||
let actions: Action[] = [];
|
||||
|
||||
signUpLogs.forEach(log => {
|
||||
actions.push({
|
||||
type: "SignUp",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: {
|
||||
stateIndex: Number(log.args._stateIndex),
|
||||
pubKey: new PubKey([log.args._userPubKeyX || 0n, log.args._userPubKeyY || 0n]),
|
||||
voiceCreditBalance: Number(log.args._voiceCreditBalance),
|
||||
timestamp: Number(log.args._timestamp),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const pollContractAddresses = new Map();
|
||||
let includesPollAddress = false;
|
||||
let pollId = 0n;
|
||||
|
||||
deployPollLogs.forEach(log => {
|
||||
const pollAddr = log.args.pollAddr?.poll;
|
||||
actions.push({
|
||||
type: "DeployPoll",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: {
|
||||
pollId: log.args._pollId,
|
||||
pollAddr,
|
||||
pubKey: new PubKey([log.args._coordinatorPubKeyX || 0n, log.args._coordinatorPubKeyY || 0n]),
|
||||
},
|
||||
});
|
||||
|
||||
if (pollContractAddress.toLowerCase() === pollAddr?.toLowerCase()) {
|
||||
includesPollAddress = true;
|
||||
pollId = log.args._pollId as bigint;
|
||||
}
|
||||
|
||||
pollContractAddresses.set(log.args._pollId, pollAddr);
|
||||
});
|
||||
|
||||
assert(includesPollAddress, "Error: the specified pollId does not exist on-chain");
|
||||
|
||||
// const pollContractAddress = pollContractAddresses.get(0n);
|
||||
const pollContract = getContract({ abi: PollAbi, address: pollContractAddress, publicClient });
|
||||
|
||||
const coordinatorPubKeyOnChain = await pollContract.read.coordinatorPubKey();
|
||||
|
||||
// assert(coordinatorPubKeyOnChain[0].toString() === coordinatorKeypair.pubKey.rawPubKey[0].toString());
|
||||
// assert(coordinatorPubKeyOnChain[1].toString() === coordinatorKeypair.pubKey.rawPubKey[1].toString());
|
||||
|
||||
const dd = await pollContract.read.getDeployTimeAndDuration();
|
||||
const deployTime = Number(dd[0]);
|
||||
const duration = Number(dd[1]);
|
||||
const onChainMaxValues = await pollContract.read.maxValues();
|
||||
const onChainTreeDepths = await pollContract.read.treeDepths();
|
||||
|
||||
const maxValues = {
|
||||
maxMessages: Number(onChainMaxValues[0]),
|
||||
maxVoteOptions: Number(onChainMaxValues[1]),
|
||||
};
|
||||
const treeDepths = {
|
||||
intStateTreeDepth: Number(onChainTreeDepths[0]),
|
||||
messageTreeDepth: Number(onChainTreeDepths[1]),
|
||||
messageTreeSubDepth: Number(onChainTreeDepths[2]),
|
||||
voteOptionTreeDepth: Number(onChainTreeDepths[3]),
|
||||
};
|
||||
const batchSizes = {
|
||||
tallyBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths[0]),
|
||||
subsidyBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths[0]),
|
||||
messageBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths[2]),
|
||||
};
|
||||
|
||||
const publishMessageLogs = await pollContract.getEvents.PublishMessage({ fromBlock: startBlock });
|
||||
const topupLogs = await pollContract.getEvents.TopupMessage({ fromBlock: startBlock });
|
||||
const mergeMaciStateAqSubRootsLogs = await pollContract.getEvents.MergeMaciStateAqSubRoots({ fromBlock: startBlock });
|
||||
const mergeMaciStateAqLogs = await pollContract.getEvents.MergeMaciStateAq({ fromBlock: startBlock });
|
||||
const mergeMessageAqSubRootsLogs = await pollContract.getEvents.MergeMessageAqSubRoots({ fromBlock: startBlock });
|
||||
const mergeMessageAqLogs = await pollContract.getEvents.MergeMessageAq({ fromBlock: startBlock });
|
||||
|
||||
publishMessageLogs.forEach(log => {
|
||||
if (log.args._message && log.args._encPubKey) {
|
||||
const message = new Message(BigInt(log.args._message.msgType), log.args._message.data as any);
|
||||
const encPubKey = new PubKey([log.args._encPubKey.x, log.args._encPubKey.y]);
|
||||
|
||||
actions.push({
|
||||
type: "PublishMessage",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: {
|
||||
message,
|
||||
encPubKey,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
topupLogs.forEach(log => {
|
||||
if (log.args._message) {
|
||||
const message = new Message(BigInt(log.args._message.msgType), log.args._message.data as any);
|
||||
actions.push({
|
||||
type: "TopupMessage",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: {
|
||||
message,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mergeMessageAqSubRootsLogs.forEach(log => {
|
||||
if (log.args._numSrQueueOps) {
|
||||
const numSrQueueOps = Number(log.args._numSrQueueOps);
|
||||
actions.push({
|
||||
type: "MergeMessageAqSubRoots",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: {
|
||||
numSrQueueOps,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// mergeMessageAqSubRootsLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLogs) as unknown as { args: { _numSrQueueOps: string } };
|
||||
|
||||
// const numSrQueueOps = Number(event.args._numSrQueueOps);
|
||||
// actions.push({
|
||||
// type: "MergeMessageAqSubRoots",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: {
|
||||
// numSrQueueOps,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
mergeMessageAqLogs.forEach(log => {
|
||||
if (log.args._messageRoot) {
|
||||
const messageRoot = BigInt(log.args._messageRoot);
|
||||
actions.push({
|
||||
type: "MergeMessageAq",
|
||||
blockNumber: log.blockNumber,
|
||||
transactionIndex: log.transactionIndex,
|
||||
data: { messageRoot },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// mergeMessageAqLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLogs);
|
||||
|
||||
// const messageRoot = BigInt((event?.args as unknown as { _messageRoot: string })._messageRoot);
|
||||
// actions.push({
|
||||
// type: "MergeMessageAq",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: { messageRoot },
|
||||
// });
|
||||
// });
|
||||
|
||||
// // Sort actions
|
||||
actions = sortActions(actions);
|
||||
|
||||
console.log(actions);
|
||||
|
||||
// // Reconstruct MaciState in order
|
||||
actions.forEach(action => {
|
||||
// console.log("action: ", action);
|
||||
switch (true) {
|
||||
case action.type === "SignUp": {
|
||||
const { pubKey, voiceCreditBalance, timestamp } = action.data;
|
||||
|
||||
maciState.signUp(pubKey!, BigInt(voiceCreditBalance!), BigInt(timestamp!));
|
||||
break;
|
||||
}
|
||||
|
||||
case action.type === "DeployPoll" && action.data.pollAddr === pollContractAddress: {
|
||||
maciState.deployPoll(
|
||||
BigInt(deployTime + duration),
|
||||
maxValues,
|
||||
treeDepths,
|
||||
batchSizes.messageBatchSize,
|
||||
coordinatorKeypair,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case action.type === "DeployPoll" && action.data.pollAddr !== pollContractAddress: {
|
||||
maciState.deployNullPoll();
|
||||
break;
|
||||
}
|
||||
|
||||
case action.type === "PublishMessage": {
|
||||
const { encPubKey, message } = action.data;
|
||||
maciState.polls.get(pollId)?.publishMessage(message!, encPubKey!);
|
||||
break;
|
||||
}
|
||||
|
||||
case action.type === "TopupMessage": {
|
||||
const { message } = action.data;
|
||||
maciState.polls.get(pollId)?.topupMessage(message!);
|
||||
break;
|
||||
}
|
||||
|
||||
// ensure that the message root is correct (i.e. all messages have been published offchain)
|
||||
case action.type === "MergeMessageAq": {
|
||||
assert(maciState.polls.get(pollId)?.messageTree.root.toString() === action.data.messageRoot?.toString());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// // Set numSignUps
|
||||
const numSignUpsAndMessages = await pollContract.read.numSignUpsAndMessages();
|
||||
console.log(numSignUpsAndMessages);
|
||||
|
||||
const poll = maciState.polls.get(pollId);
|
||||
|
||||
// // ensure all messages were recorded
|
||||
assert(Number(numSignUpsAndMessages[1]) === poll?.messages.length);
|
||||
// set the number of signups
|
||||
poll.updatePoll(numSignUpsAndMessages[0]);
|
||||
|
||||
// // we need to ensure that the stateRoot is correct
|
||||
assert(poll.stateTree?.root.toString() === (await pollContract.read.mergedStateRoot()).toString());
|
||||
|
||||
maciState.polls.set(pollId, poll);
|
||||
|
||||
return maciState;
|
||||
}
|
||||
|
||||
// async function (provider: Provider,
|
||||
// address: string,
|
||||
// coordinatorKeypair: Keypair,
|
||||
// pollId: bigint,
|
||||
// fromBlock = 0,
|
||||
// blocksPerRequest = 50,
|
||||
// endBlock: number | undefined = undefined,
|
||||
// sleepAmount: number | undefined = undefined,
|
||||
// ): Promise<MaciState> {
|
||||
// // ensure the pollId is valid
|
||||
// assert(pollId >= 0);
|
||||
|
||||
// const [pollContractAbi] = parseArtifact("Poll");
|
||||
// const [maciContractAbi] = parseArtifact("MACI");
|
||||
|
||||
// const maciContract = new BaseContract(address, maciContractAbi, provider) as MACI;
|
||||
|
||||
// const maciIface = new Interface(maciContractAbi);
|
||||
// const pollIface = new Interface(pollContractAbi);
|
||||
|
||||
// // Check stateTreeDepth
|
||||
// const stateTreeDepth = await maciContract.stateTreeDepth();
|
||||
|
||||
// // we need to pass the stateTreeDepth
|
||||
// const maciState = new MaciState(Number(stateTreeDepth));
|
||||
// // ensure it is set correctly
|
||||
// assert(stateTreeDepth === BigInt(maciState.stateTreeDepth));
|
||||
|
||||
// let signUpLogs: Log[] = [];
|
||||
// let deployPollLogs: Log[] = [];
|
||||
|
||||
// // if no last block is set then we fetch until the current block number
|
||||
// const lastBlock = endBlock || (await provider.getBlockNumber());
|
||||
|
||||
// // Fetch event logs in batches (lastBlock inclusive)
|
||||
// for (let i = fromBlock; i <= lastBlock; i += blocksPerRequest + 1) {
|
||||
// // the last block batch will be either current iteration block + blockPerRequest
|
||||
// // or the end block if it is set
|
||||
// const toBlock = i + blocksPerRequest >= lastBlock ? lastBlock : i + blocksPerRequest;
|
||||
|
||||
// const [tmpSignUpLogs, tmpDeployPollLogs] =
|
||||
// // eslint-disable-next-line no-await-in-loop
|
||||
// await Promise.all([
|
||||
// maciContract.queryFilter(maciContract.filters.SignUp(), i, toBlock),
|
||||
// maciContract.queryFilter(maciContract.filters.DeployPoll(), i, toBlock),
|
||||
// ]);
|
||||
|
||||
// signUpLogs = signUpLogs.concat(tmpSignUpLogs);
|
||||
// deployPollLogs = deployPollLogs.concat(tmpDeployPollLogs);
|
||||
|
||||
// if (sleepAmount) {
|
||||
// // eslint-disable-next-line no-await-in-loop
|
||||
// await sleep(sleepAmount);
|
||||
// }
|
||||
// }
|
||||
|
||||
// let actions: Action[] = [];
|
||||
|
||||
// signUpLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLog = { ...log, topics: [...log.topics] };
|
||||
// const event = maciIface.parseLog(mutableLog) as unknown as {
|
||||
// args: {
|
||||
// _stateIndex: number;
|
||||
// _userPubKeyX: string;
|
||||
// _userPubKeyY: string;
|
||||
// _voiceCreditBalance: number;
|
||||
// _timestamp: number;
|
||||
// };
|
||||
// };
|
||||
|
||||
// actions.push({
|
||||
// type: "SignUp",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: {
|
||||
// stateIndex: Number(event.args._stateIndex),
|
||||
// pubKey: new PubKey([BigInt(event.args._userPubKeyX), BigInt(event.args._userPubKeyY)]),
|
||||
// voiceCreditBalance: Number(event.args._voiceCreditBalance),
|
||||
// timestamp: Number(event.args._timestamp),
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// let index = 0n;
|
||||
// const foundPollIds: number[] = [];
|
||||
// const pollContractAddresses = new Map<bigint, string>();
|
||||
|
||||
// deployPollLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = maciIface.parseLog(mutableLogs) as unknown as {
|
||||
// args: {
|
||||
// _coordinatorPubKeyX: string;
|
||||
// _coordinatorPubKeyY: string;
|
||||
// _pollId: bigint;
|
||||
// pollAddr: {
|
||||
// poll: string;
|
||||
// messageProcessor: string;
|
||||
// tally: string;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
|
||||
// const pubKey = new PubKey([BigInt(event.args._coordinatorPubKeyX), BigInt(event.args._coordinatorPubKeyY)]);
|
||||
|
||||
// const p = event.args._pollId;
|
||||
// assert(p === index);
|
||||
|
||||
// const pollAddr = event.args.pollAddr.poll;
|
||||
// actions.push({
|
||||
// type: "DeployPoll",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: { pollId: p, pollAddr, pubKey },
|
||||
// });
|
||||
|
||||
// foundPollIds.push(Number(p));
|
||||
// pollContractAddresses.set(BigInt(p), pollAddr);
|
||||
// index += 1n;
|
||||
// });
|
||||
|
||||
// Check whether each pollId exists
|
||||
// assert(foundPollIds.includes(Number(pollId)), "Error: the specified pollId does not exist on-chain");
|
||||
|
||||
// const pollContractAddress = pollContractAddresses.get(pollId)!;
|
||||
// const pollContract = new BaseContract(pollContractAddress, pollContractAbi, provider) as Poll;
|
||||
|
||||
// const coordinatorPubKeyOnChain = await pollContract.coordinatorPubKey();
|
||||
// assert(coordinatorPubKeyOnChain[0].toString() === coordinatorKeypair.pubKey.rawPubKey[0].toString());
|
||||
// assert(coordinatorPubKeyOnChain[1].toString() === coordinatorKeypair.pubKey.rawPubKey[1].toString());
|
||||
|
||||
// const dd = await pollContract.getDeployTimeAndDuration();
|
||||
// const deployTime = Number(dd[0]);
|
||||
// const duration = Number(dd[1]);
|
||||
// const onChainMaxValues = await pollContract.maxValues();
|
||||
// const onChainTreeDepths = await pollContract.treeDepths();
|
||||
|
||||
// const maxValues = {
|
||||
// maxMessages: Number(onChainMaxValues.maxMessages),
|
||||
// maxVoteOptions: Number(onChainMaxValues.maxVoteOptions),
|
||||
// };
|
||||
// const treeDepths = {
|
||||
// intStateTreeDepth: Number(onChainTreeDepths.intStateTreeDepth),
|
||||
// messageTreeDepth: Number(onChainTreeDepths.messageTreeDepth),
|
||||
// messageTreeSubDepth: Number(onChainTreeDepths.messageTreeSubDepth),
|
||||
// voteOptionTreeDepth: Number(onChainTreeDepths.voteOptionTreeDepth),
|
||||
// };
|
||||
// const batchSizes = {
|
||||
// tallyBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths.intStateTreeDepth),
|
||||
// subsidyBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths.intStateTreeDepth),
|
||||
// messageBatchSize: STATE_TREE_ARITY ** Number(onChainTreeDepths.messageTreeSubDepth),
|
||||
// };
|
||||
|
||||
// // fetch poll contract logs
|
||||
// let publishMessageLogs: Log[] = [];
|
||||
// let topupLogs: Log[] = [];
|
||||
// let mergeMaciStateAqSubRootsLogs: Log[] = [];
|
||||
// let mergeMaciStateAqLogs: Log[] = [];
|
||||
// let mergeMessageAqSubRootsLogs: Log[] = [];
|
||||
// let mergeMessageAqLogs: Log[] = [];
|
||||
|
||||
// for (let i = fromBlock; i <= lastBlock; i += blocksPerRequest + 1) {
|
||||
// const toBlock = i + blocksPerRequest >= lastBlock ? lastBlock : i + blocksPerRequest;
|
||||
|
||||
// const [
|
||||
// tmpPublishMessageLogs,
|
||||
// tmpTopupLogs,
|
||||
// tmpMergeMaciStateAqSubRootsLogs,
|
||||
// tmpMergeMaciStateAqLogs,
|
||||
// tmpMergeMessageAqSubRootsLogs,
|
||||
// tmpMergeMessageAqLogs,
|
||||
// // eslint-disable-next-line no-await-in-loop
|
||||
// ] = await Promise.all([
|
||||
// pollContract.queryFilter(pollContract.filters.PublishMessage(), i, toBlock),
|
||||
// pollContract.queryFilter(pollContract.filters.TopupMessage(), i, toBlock),
|
||||
// pollContract.queryFilter(pollContract.filters.MergeMaciStateAqSubRoots(), i, toBlock),
|
||||
// pollContract.queryFilter(pollContract.filters.MergeMaciStateAq(), i, toBlock),
|
||||
// pollContract.queryFilter(pollContract.filters.MergeMessageAqSubRoots(), i, toBlock),
|
||||
// pollContract.queryFilter(pollContract.filters.MergeMessageAq(), i, toBlock),
|
||||
// ]);
|
||||
|
||||
// publishMessageLogs = publishMessageLogs.concat(tmpPublishMessageLogs);
|
||||
// topupLogs = topupLogs.concat(tmpTopupLogs);
|
||||
// mergeMaciStateAqSubRootsLogs = mergeMaciStateAqSubRootsLogs.concat(tmpMergeMaciStateAqSubRootsLogs);
|
||||
// mergeMaciStateAqLogs = mergeMaciStateAqLogs.concat(tmpMergeMaciStateAqLogs);
|
||||
// mergeMessageAqSubRootsLogs = mergeMessageAqSubRootsLogs.concat(tmpMergeMessageAqSubRootsLogs);
|
||||
// mergeMessageAqLogs = mergeMessageAqLogs.concat(tmpMergeMessageAqLogs);
|
||||
|
||||
// if (sleepAmount) {
|
||||
// // eslint-disable-next-line no-await-in-loop
|
||||
// await sleep(sleepAmount);
|
||||
// }
|
||||
// }
|
||||
|
||||
// publishMessageLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLogs) as unknown as {
|
||||
// args: { _message: [string, string[]]; _encPubKey: string[] };
|
||||
// };
|
||||
|
||||
// const message = new Message(
|
||||
// BigInt(event.args._message[0]),
|
||||
|
||||
// event.args._message[1].map(x => BigInt(x)),
|
||||
// );
|
||||
|
||||
// const encPubKey = new PubKey(event.args._encPubKey.map(x => BigInt(x.toString())) as [bigint, bigint]);
|
||||
|
||||
// actions.push({
|
||||
// type: "PublishMessage",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: {
|
||||
// message,
|
||||
// encPubKey,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// topupLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLog = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLog) as unknown as {
|
||||
// args: { _message: [string, string[]] };
|
||||
// };
|
||||
// const message = new Message(
|
||||
// BigInt(event.args._message[0]),
|
||||
// event.args._message[1].map(x => BigInt(x)),
|
||||
// );
|
||||
|
||||
// actions.push({
|
||||
// type: "TopupMessage",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: {
|
||||
// message,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// mergeMessageAqSubRootsLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLogs) as unknown as { args: { _numSrQueueOps: string } };
|
||||
|
||||
// const numSrQueueOps = Number(event.args._numSrQueueOps);
|
||||
// actions.push({
|
||||
// type: "MergeMessageAqSubRoots",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: {
|
||||
// numSrQueueOps,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// mergeMessageAqLogs.forEach(log => {
|
||||
// assert(!!log);
|
||||
// const mutableLogs = { ...log, topics: [...log.topics] };
|
||||
// const event = pollIface.parseLog(mutableLogs);
|
||||
|
||||
// const messageRoot = BigInt((event?.args as unknown as { _messageRoot: string })._messageRoot);
|
||||
// actions.push({
|
||||
// type: "MergeMessageAq",
|
||||
// blockNumber: log.blockNumber,
|
||||
// transactionIndex: log.transactionIndex,
|
||||
// data: { messageRoot },
|
||||
// });
|
||||
// });
|
||||
|
||||
// // Sort actions
|
||||
// actions = sortActions(actions);
|
||||
|
||||
// // Reconstruct MaciState in order
|
||||
// actions.forEach(action => {
|
||||
// switch (true) {
|
||||
// case action.type === "SignUp": {
|
||||
// const { pubKey, voiceCreditBalance, timestamp } = action.data;
|
||||
|
||||
// maciState.signUp(pubKey!, BigInt(voiceCreditBalance!), BigInt(timestamp!));
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case action.type === "DeployPoll" && action.data.pollId?.toString() === pollId.toString(): {
|
||||
// maciState.deployPoll(
|
||||
// BigInt(deployTime + duration),
|
||||
// maxValues,
|
||||
// treeDepths,
|
||||
// batchSizes.messageBatchSize,
|
||||
// coordinatorKeypair,
|
||||
// );
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case action.type === "DeployPoll" && action.data.pollId?.toString() !== pollId.toString(): {
|
||||
// maciState.deployNullPoll();
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case action.type === "PublishMessage": {
|
||||
// const { encPubKey, message } = action.data;
|
||||
// maciState.polls.get(pollId)?.publishMessage(message!, encPubKey!);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// case action.type === "TopupMessage": {
|
||||
// const { message } = action.data;
|
||||
// maciState.polls.get(pollId)?.topupMessage(message!);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // ensure that the message root is correct (i.e. all messages have been published offchain)
|
||||
// case action.type === "MergeMessageAq": {
|
||||
// assert(maciState.polls.get(pollId)?.messageTree.root.toString() === action.data.messageRoot?.toString());
|
||||
// break;
|
||||
// }
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Set numSignUps
|
||||
// const numSignUpsAndMessages = await pollContract.numSignUpsAndMessages();
|
||||
|
||||
// const poll = maciState.polls.get(pollId);
|
||||
|
||||
// // ensure all messages were recorded
|
||||
// assert(Number(numSignUpsAndMessages[1]) === poll?.messages.length);
|
||||
// // set the number of signups
|
||||
// poll.updatePoll(numSignUpsAndMessages[0]);
|
||||
|
||||
// // we need to ensure that the stateRoot is correct
|
||||
// assert(poll.stateTree?.root.toString() === (await pollContract.mergedStateRoot()).toString());
|
||||
|
||||
// maciState.polls.set(pollId, poll);
|
||||
|
||||
// return maciState;
|
||||
// }
|
||||
93
packages/nextjs/utils/mergeMessages.ts
Normal file
93
packages/nextjs/utils/mergeMessages.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { DEFAULT_SR_QUEUE_OPS } from "./mergeSignups";
|
||||
import { createPublicClient, createWalletClient, getContract, http } from "viem";
|
||||
import { privateKeyToAddress } from "viem/accounts";
|
||||
import AccQueueAbi from "~~/abi/AccQueue";
|
||||
import PollAbi from "~~/abi/Poll";
|
||||
import deployedContracts from "~~/contracts/deployedContracts";
|
||||
import scaffoldConfig from "~~/scaffold.config";
|
||||
|
||||
export const mergeMessages = async ({
|
||||
pollContractAddress,
|
||||
numQueueOps,
|
||||
}: {
|
||||
pollContractAddress: string;
|
||||
numQueueOps?: number;
|
||||
}): Promise<void> => {
|
||||
const chain = scaffoldConfig.targetNetworks[0];
|
||||
const publicClient = createPublicClient({ chain, transport: http() });
|
||||
const ownerAddress = privateKeyToAddress(process.env.OWNER_PRIVATE_KEY as `0x${string}`);
|
||||
const walletClient = createWalletClient({
|
||||
chain,
|
||||
transport: http(),
|
||||
key: process.env.OWNER_PRIVATE_KEY,
|
||||
account: ownerAddress,
|
||||
});
|
||||
const { address: MaciAddress, abi: MaciAbi, deploymentBlockNumber } = deployedContracts[chain.id].MACI;
|
||||
|
||||
const maciContract = getContract({ abi: MaciAbi, address: MaciAddress, publicClient, walletClient });
|
||||
const pollId = await maciContract.read.getPollId([pollContractAddress]);
|
||||
|
||||
const pollContract = getContract({ abi: PollAbi, address: pollContractAddress, publicClient, walletClient });
|
||||
|
||||
const extContracts = await pollContract.read.extContracts();
|
||||
const messageAqContractAddr = extContracts[1];
|
||||
|
||||
const accQueueContract = getContract({
|
||||
abi: AccQueueAbi,
|
||||
address: messageAqContractAddr,
|
||||
publicClient,
|
||||
walletClient,
|
||||
});
|
||||
|
||||
// check if it's time to merge the message AQ
|
||||
const dd = await pollContract.read.getDeployTimeAndDuration();
|
||||
const deadline = Number(dd[0]) + Number(dd[1]);
|
||||
const { timestamp: now } = await publicClient.getBlock();
|
||||
|
||||
if (now < deadline) {
|
||||
console.error("Voting period is not over");
|
||||
}
|
||||
|
||||
let subTreesMerged = false;
|
||||
|
||||
// infinite loop to merge the sub trees
|
||||
while (!subTreesMerged) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
subTreesMerged = await accQueueContract.read.subTreesMerged();
|
||||
|
||||
if (subTreesMerged) {
|
||||
console.log("All message subtrees have been merged.");
|
||||
} else {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await accQueueContract.read
|
||||
.getSrIndices()
|
||||
.then(data => data.map(x => Number(x)))
|
||||
.then(indices => {
|
||||
console.log(`Merging message subroots ${indices[0] + 1} / ${indices[1] + 1}`);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const tx = await pollContract.write.mergeMessageAqSubRoots([BigInt(numQueueOps || DEFAULT_SR_QUEUE_OPS)]);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
|
||||
console.log(`Transaction hash: ${tx}`);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the message AQ has been fully merged
|
||||
const messageTreeDepth = Number((await pollContract.read.treeDepths())[2]);
|
||||
|
||||
// check if the main root was not already computed
|
||||
const mainRoot = (await accQueueContract.read.getMainRoot([BigInt(messageTreeDepth)])).toString();
|
||||
if (mainRoot === "0") {
|
||||
// go and merge the message tree
|
||||
|
||||
console.log("Merging subroots to a main message root...");
|
||||
const tx = await pollContract.write.mergeMessageAq();
|
||||
|
||||
console.log(`Executed mergeMessageAq(); Transaction hash: ${tx}`);
|
||||
console.log("The message tree has been merged.");
|
||||
} else {
|
||||
console.log("The message tree has already been merged.");
|
||||
}
|
||||
};
|
||||
106
packages/nextjs/utils/mergeSignups.ts
Normal file
106
packages/nextjs/utils/mergeSignups.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { createPublicClient, createWalletClient, getContract, http } from "viem";
|
||||
import { privateKeyToAddress } from "viem/accounts";
|
||||
import AccQueueAbi from "~~/abi/AccQueue";
|
||||
import PollAbi from "~~/abi/Poll";
|
||||
import deployedContracts from "~~/contracts/deployedContracts";
|
||||
import scaffoldConfig from "~~/scaffold.config";
|
||||
|
||||
export const DEFAULT_SR_QUEUE_OPS = 4;
|
||||
|
||||
export const mergeSignups = async ({
|
||||
pollContractAddress,
|
||||
numQueueOps,
|
||||
}: {
|
||||
pollContractAddress: string;
|
||||
numQueueOps?: number;
|
||||
}): Promise<void> => {
|
||||
const chain = scaffoldConfig.targetNetworks[0];
|
||||
const publicClient = createPublicClient({ chain, transport: http() });
|
||||
const ownerAddress = privateKeyToAddress(process.env.OWNER_PRIVATE_KEY as `0x${string}`);
|
||||
const walletClient = createWalletClient({
|
||||
chain,
|
||||
transport: http(),
|
||||
key: process.env.OWNER_PRIVATE_KEY,
|
||||
account: ownerAddress,
|
||||
});
|
||||
const { address: MaciAddress, abi: MaciAbi, deploymentBlockNumber } = deployedContracts[chain.id].MACI;
|
||||
|
||||
const maciContract = getContract({ abi: MaciAbi, address: MaciAddress, publicClient, walletClient });
|
||||
const pollId = await maciContract.read.getPollId([pollContractAddress]);
|
||||
|
||||
const pollContract = getContract({ abi: PollAbi, address: pollContractAddress, publicClient, walletClient });
|
||||
|
||||
// if (pollId < 0) {
|
||||
// logError("Invalid poll id");
|
||||
// }
|
||||
|
||||
// const pollAddress = await maciContract.polls(pollId);
|
||||
|
||||
const accQueueContract = getContract({
|
||||
abi: AccQueueAbi,
|
||||
address: await maciContract.read.stateAq(),
|
||||
publicClient,
|
||||
walletClient,
|
||||
});
|
||||
|
||||
// const accQueueContract = AccQueueFactory.connect(await maciContract.stateAq(), signer);
|
||||
|
||||
// check if it's time to merge the message AQ
|
||||
const dd = await pollContract.read.getDeployTimeAndDuration();
|
||||
const deadline = Number(dd[0]) + Number(dd[1]);
|
||||
const { timestamp: now } = await publicClient.getBlock();
|
||||
|
||||
if (now < deadline) {
|
||||
console.error("Voting period is not over");
|
||||
}
|
||||
|
||||
let subTreesMerged = false;
|
||||
|
||||
// infinite loop to merge the sub trees
|
||||
while (!subTreesMerged) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
subTreesMerged = await accQueueContract.read.subTreesMerged();
|
||||
|
||||
if (subTreesMerged) {
|
||||
console.log("All state subtrees have been merged.");
|
||||
} else {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await accQueueContract.read
|
||||
.getSrIndices()
|
||||
.then(data => data.map(x => Number(x)))
|
||||
.then(indices => {
|
||||
console.log(`Merging state subroots ${indices[0] + 1} / ${indices[1] + 1}`);
|
||||
});
|
||||
|
||||
// first merge the subroots
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const tx = await pollContract.write.mergeMaciStateAqSubRoots([
|
||||
BigInt(numQueueOps || DEFAULT_SR_QUEUE_OPS),
|
||||
pollId,
|
||||
]);
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
// const receipt = await tx.wait();
|
||||
|
||||
// if (receipt?.status !== 1) {
|
||||
// logError("Error merging state subroots");
|
||||
// }
|
||||
|
||||
// logYellow(quiet, info(`Transaction hash: ${receipt!.hash}`));
|
||||
// logGreen(quiet, success(`Executed mergeMaciStateAqSubRoots(); gas used: ${receipt!.gasUsed.toString()}`));
|
||||
}
|
||||
}
|
||||
|
||||
// check if the state AQ has been fully merged
|
||||
const stateTreeDepth = await maciContract.read.stateTreeDepth();
|
||||
const mainRoot = (await accQueueContract.read.getMainRoot([BigInt(stateTreeDepth)])).toString();
|
||||
|
||||
if (mainRoot === "0" || pollId > 0) {
|
||||
// go and merge the state tree
|
||||
console.log("Merging subroots to a main state root...");
|
||||
const tx = await pollContract.write.mergeMaciStateAq([pollId]);
|
||||
|
||||
console.log(`Transaction hash: ${tx}`);
|
||||
} else {
|
||||
console.log("The state tree has already been merged.");
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user