"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable no-await-in-loop */
/* eslint-disable no-console */
const config_1 = require("hardhat/config");
const fs_1 = __importDefault(require("fs"));
const logger_1 = require("../../ts/logger");
const proofs_1 = require("../../ts/proofs");
const ContractStorage_1 = require("../helpers/ContractStorage");
const Deployment_1 = require("../helpers/Deployment");
const Prover_1 = require("../helpers/Prover");
const types_1 = require("../helpers/types");
/**
 * Prove hardhat task for submitting proofs on-chain as well as uploading tally results
 */
(0, config_1.task)("submitOnChain", "Command to prove the result of a poll on-chain")
    .addParam("poll", "The poll id", undefined, config_1.types.string)
    .addParam("outputDir", "Output directory for proofs", undefined, config_1.types.string)
    .addParam("tallyFile", "The file to store the tally proof", undefined, config_1.types.string)
    .setAction(async ({ outputDir, poll, tallyFile }, hre) => {
    const deployment = Deployment_1.Deployment.getInstance();
    deployment.setHre(hre);
    deployment.setContractNames(types_1.EContracts);
    const storage = ContractStorage_1.ContractStorage.getInstance();
    // if we do not have the output directory just create it
    const isOutputDirExists = fs_1.default.existsSync(outputDir);
    if (!isOutputDirExists) {
        // Create the directory
        throw new Error(`Output directory ${outputDir} does not exist. You must provide a valid directory containing the poll zk-SNARK proofs.`);
    }
    const signer = await deployment.getDeployer();
    const { network } = hre;
    const startBalance = await signer.provider.getBalance(signer);
    (0, logger_1.logMagenta)({ text: (0, logger_1.info)(`Start balance: ${Number(startBalance / 10n ** 12n) / 1e6}`) });
    const maciContractAddress = storage.mustGetAddress(types_1.EContracts.MACI, network.name);
    const [maciContract, verifyingKeysRegistryContract, verifierContract] = await Promise.all([
        deployment.getContract({
            name: types_1.EContracts.MACI,
            address: maciContractAddress,
        }),
        deployment.getContract({ name: types_1.EContracts.VerifyingKeysRegistry }),
        deployment.getContract({ name: types_1.EContracts.Verifier }),
    ]);
    const pollContracts = await maciContract.polls(poll);
    const pollContract = await deployment.getContract({
        name: types_1.EContracts.Poll,
        address: pollContracts.poll,
    });
    const [isStateAqMerged, messageProcessorContract, tallyContract] = await Promise.all([
        pollContract.stateMerged(),
        deployment.getContract({
            name: types_1.EContracts.MessageProcessor,
            address: pollContracts.messageProcessor,
        }),
        deployment.getContract({
            name: types_1.EContracts.Tally,
            address: pollContracts.tally,
        }),
    ]);
    // Check that the state and message trees have been merged for at least the first poll
    if (!isStateAqMerged && poll.toString() === "0") {
        throw new Error("The state tree has not been merged yet. Please use the mergeSignups subcommand to do so.");
    }
    const data = {
        processProofs: [],
        tallyProofs: [],
    };
    // read the proofs from the output directory
    const files = await fs_1.default.promises.readdir(outputDir);
    // Read process proofs
    data.processProofs = await (0, proofs_1.readProofs)({ files, folder: outputDir, type: "process" });
    // Read tally proofs
    data.tallyProofs = await (0, proofs_1.readProofs)({ files, folder: outputDir, type: "tally" });
    const prover = new Prover_1.Prover({
        maciContract,
        messageProcessorContract,
        pollContract,
        verifyingKeysRegistryContract,
        verifierContract,
        tallyContract,
    });
    await prover.proveMessageProcessing(data.processProofs);
    // read tally data
    const tallyData = await fs_1.default.promises
        .readFile(tallyFile, "utf8")
        .then((result) => JSON.parse(result));
    await prover.proveTally(data.tallyProofs);
    const voteOptions = await pollContract.voteOptions();
    await prover.submitResults(tallyData, Number.parseInt(voteOptions.toString(), 10));
    const endBalance = await signer.provider.getBalance(signer);
    (0, logger_1.logMagenta)({ text: (0, logger_1.info)(`End balance: ${Number(endBalance / 10n ** 12n) / 1e6}`) });
    (0, logger_1.logMagenta)({ text: (0, logger_1.info)(`Prove expenses: ${Number((startBalance - endBalance) / 10n ** 12n) / 1e6}`) });
});
//# sourceMappingURL=submitOnChain.js.map