"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable no-console */
const core_1 = require("@maci-protocol/core");
const domainobjs_1 = require("@maci-protocol/domainobjs");
const ethers_1 = require("ethers");
const proofs_1 = require("../../../ts/proofs");
const constants_1 = require("../../helpers/constants");
const ContractStorage_1 = require("../../helpers/ContractStorage");
const Deployment_1 = require("../../helpers/Deployment");
const types_1 = require("../../helpers/types");
const deployment = Deployment_1.Deployment.getInstance();
const storage = ContractStorage_1.ContractStorage.getInstance();
/**
 * Deploy step registration and task itself
 */
deployment.deployTask(constants_1.EDeploySteps.Poll, "Deploy poll").then((task) => task.setAction(async (_, hre) => {
    deployment.setHre(hre);
    const maciContractAddress = storage.getAddress(types_1.EContracts.MACI, hre.network.name);
    const verifierContractAddress = storage.getAddress(types_1.EContracts.Verifier, hre.network.name);
    const verifyingKeysRegistryContractAddress = storage.getAddress(types_1.EContracts.VerifyingKeysRegistry, hre.network.name);
    if (!maciContractAddress) {
        throw new Error("Need to deploy MACI contract first");
    }
    if (!verifierContractAddress) {
        throw new Error("Need to deploy Verifier contract first");
    }
    if (!verifyingKeysRegistryContractAddress) {
        throw new Error("Need to deploy VerifyingKeysRegistry contract first");
    }
    const maciContract = await deployment.getContract({ name: types_1.EContracts.MACI });
    const pollId = await maciContract.nextPollId();
    const coordinatorPublicKey = deployment.getDeployConfigField(types_1.EContracts.Poll, "coordinatorPublicKey");
    const pollStartTimestamp = deployment.getDeployConfigField(types_1.EContracts.Poll, "pollStartDate");
    const pollEndTimestamp = deployment.getDeployConfigField(types_1.EContracts.Poll, "pollEndDate");
    const tallyProcessingStateTreeDepth = deployment.getDeployConfigField(types_1.EContracts.VerifyingKeysRegistry, "tallyProcessingStateTreeDepth");
    const messageBatchSize = deployment.getDeployConfigField(types_1.EContracts.VerifyingKeysRegistry, "messageBatchSize");
    const stateTreeDepth = deployment.getDeployConfigField(types_1.EContracts.Poll, "stateTreeDepth") ||
        (await maciContract.stateTreeDepth());
    const voteOptionTreeDepth = deployment.getDeployConfigField(types_1.EContracts.VerifyingKeysRegistry, "voteOptionTreeDepth");
    const relayers = deployment
        .getDeployConfigField(types_1.EContracts.Poll, "relayers")
        ?.split(",")
        .map((value) => value.trim()) || [ethers_1.ZeroAddress];
    const mode = deployment.getDeployConfigField(types_1.EContracts.Poll, "mode") ?? core_1.EMode.QV;
    const unserializedKey = domainobjs_1.PublicKey.deserialize(coordinatorPublicKey);
    const policy = deployment.getDeployConfigField(types_1.EContracts.Poll, "policy") || types_1.EContracts.FreeForAllPolicy;
    const fullPolicyName = constants_1.FULL_POLICY_NAMES[policy];
    const policyContractAddress = storage.mustGetAddress(fullPolicyName, hre.network.name, `poll-${pollId}`);
    const initialVoiceCreditProxy = deployment.getDeployConfigField(types_1.EContracts.Poll, "initialVoiceCreditProxy") ||
        types_1.EContracts.ConstantInitialVoiceCreditProxy;
    const initialVoiceCreditProxyContractAddress = storage.mustGetAddress(initialVoiceCreditProxy, hre.network.name);
    const voteOptions = deployment.getDeployConfigField(types_1.EContracts.Poll, "voteOptions");
    const verifyingKeysRegistryContract = await deployment.getContract({
        name: types_1.EContracts.VerifyingKeysRegistry,
        address: verifyingKeysRegistryContractAddress,
    });
    const pollJoiningZkeyPath = deployment.getDeployConfigField(types_1.EContracts.VerifyingKeysRegistry, "zkeys.pollJoiningZkey.zkey");
    const pollJoinedZkeyPath = deployment.getDeployConfigField(types_1.EContracts.VerifyingKeysRegistry, "zkeys.pollJoinedZkey.zkey");
    const [pollJoiningVerifyingKey, pollJoinedVerifyingKey] = await Promise.all([
        pollJoiningZkeyPath && (0, proofs_1.extractVerifyingKey)(pollJoiningZkeyPath),
        pollJoinedZkeyPath && (0, proofs_1.extractVerifyingKey)(pollJoinedZkeyPath),
    ]).then((verifyingKeys) => verifyingKeys.map((verifyingKey) => verifyingKey && domainobjs_1.VerifyingKey.fromObj(verifyingKey)));
    if (!pollJoiningVerifyingKey) {
        throw new Error("Poll joining zkey is not set");
    }
    if (!pollJoinedVerifyingKey) {
        throw new Error("Poll joined zkey is not set");
    }
    const [pollJoiningVerifyingKeySignature, pollJoinedVerifyingKeySignature] = await Promise.all([
        verifyingKeysRegistryContract.generatePollJoiningVerifyingKeySignature(stateTreeDepth),
        verifyingKeysRegistryContract.generatePollJoinedVerifyingKeySignature(stateTreeDepth),
    ]);
    const [pollJoiningVerifyingKeyOnchain, pollJoinedVerifyingKeyOnchain] = await Promise.all([
        verifyingKeysRegistryContract.getPollJoiningVerifyingKeyBySignature(pollJoiningVerifyingKeySignature),
        verifyingKeysRegistryContract.getPollJoinedVerifyingKeyBySignature(pollJoinedVerifyingKeySignature),
    ]);
    const isPollJoiningVerifyingKeySet = pollJoiningVerifyingKey.equals(domainobjs_1.VerifyingKey.fromContract(pollJoiningVerifyingKeyOnchain));
    if (!isPollJoiningVerifyingKeySet) {
        await verifyingKeysRegistryContract
            .setPollJoiningVerifyingKey(stateTreeDepth, pollJoiningVerifyingKey.asContractParam())
            .then((tx) => tx.wait());
    }
    const isPollJoinedVerifyingKeySet = pollJoinedVerifyingKey.equals(domainobjs_1.VerifyingKey.fromContract(pollJoinedVerifyingKeyOnchain));
    if (!isPollJoinedVerifyingKeySet) {
        await verifyingKeysRegistryContract
            .setPollJoinedVerifyingKey(stateTreeDepth, pollJoinedVerifyingKey.asContractParam())
            .then((tx) => tx.wait());
    }
    const receipt = await maciContract
        .deployPoll({
        startDate: pollStartTimestamp,
        endDate: pollEndTimestamp,
        treeDepths: {
            tallyProcessingStateTreeDepth,
            voteOptionTreeDepth,
            stateTreeDepth,
        },
        messageBatchSize,
        coordinatorPublicKey: unserializedKey.asContractParam(),
        verifier: verifierContractAddress,
        verifyingKeysRegistry: verifyingKeysRegistryContractAddress,
        mode,
        policy: policyContractAddress,
        initialVoiceCreditProxy: initialVoiceCreditProxyContractAddress,
        relayers,
        voteOptions,
    })
        .then((tx) => tx.wait());
    if (receipt?.status !== 1) {
        throw new Error("Deploy poll transaction is failed");
    }
    const pollContracts = await maciContract.getPoll(pollId);
    const pollContractAddress = pollContracts.poll;
    const messageProcessorContractAddress = pollContracts.messageProcessor;
    const tallyContractAddress = pollContracts.tally;
    const pollContract = await deployment.getContract({ name: types_1.EContracts.Poll, address: pollContractAddress });
    const policyContract = await deployment.getContract({
        name: fullPolicyName,
        address: policyContractAddress,
    });
    await policyContract.setTarget(pollContractAddress).then((tx) => tx.wait());
    const messageProcessorContract = await deployment.getContract({
        name: types_1.EContracts.MessageProcessor,
        address: messageProcessorContractAddress,
    });
    const tallyContract = await deployment.getContract({
        name: types_1.EContracts.Tally,
        address: tallyContractAddress,
    });
    const [pollFactory, messageProcessorFactory, tallyFactory] = await Promise.all([
        deployment.getContract({
            name: types_1.EContracts.PollFactory,
        }),
        deployment.getContract({
            name: types_1.EContracts.MessageProcessorFactory,
        }),
        deployment.getContract({
            name: types_1.EContracts.TallyFactory,
        }),
    ]);
    const [pollImplementation, messageProcessorImplementation, tallyImplementation] = await Promise.all([
        pollFactory.IMPLEMENTATION(),
        messageProcessorFactory.IMPLEMENTATION(),
        tallyFactory.IMPLEMENTATION(),
    ]);
    await Promise.all([
        storage.register({
            id: types_1.EContracts.Poll,
            key: `poll-${pollId}`,
            implementation: pollImplementation,
            contract: pollContract,
            args: [],
            network: hre.network.name,
        }),
        storage.register({
            id: types_1.EContracts.MessageProcessor,
            key: `poll-${pollId}`,
            implementation: messageProcessorImplementation,
            contract: messageProcessorContract,
            args: [],
            network: hre.network.name,
        }),
        storage.register({
            id: types_1.EContracts.Tally,
            key: `poll-${pollId}`,
            implementation: tallyImplementation,
            contract: tallyContract,
            args: [],
            network: hre.network.name,
        }),
    ]);
}));
//# sourceMappingURL=03-poll.js.map