"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ethers_1 = require("ethers");
const constants_1 = require("../src/constants");
const utils_1 = require("../src/utils");
const src_1 = require("../src");
const shared_1 = require("../deployConfig/shared");
/**
 * Hardhat task defining the contract deployments for Connext
 *
 * @param hre Hardhat environment to deploy to
 */
const func = async (hre) => {
    const chainId = await hre.getChainId();
    const acceptanceDelay = constants_1.SKIP_SETUP.includes(parseInt(chainId)) ? 604800 : 0; // 604800 = 7 days
    let _deployer;
    ({ deployer: _deployer } = await hre.ethers.getNamedSigners());
    if (!_deployer) {
        [_deployer] = await hre.ethers.getUnnamedSigners();
    }
    const deployer = _deployer;
    console.log("\n============================= Deploying Connext Contracts ===============================");
    console.log("deployer: ", deployer.address);
    console.log("acceptance delay: ", acceptanceDelay);
    const network = await hre.ethers.provider.getNetwork();
    console.log("network: ", network);
    const domain = (0, src_1.chainIdToDomain)(network.chainId);
    console.log("domain: ", domain);
    const price = await hre.ethers.provider.getGasPrice();
    console.log("price: ", price.toString());
    const zksync = hre.network.config.zksync || false;
    console.log("zksync: ", zksync);
    const balance = await hre.ethers.provider.getBalance(deployer.address);
    console.log("balance: ", balance.toString());
    // Get connector manager
    const messagingNetwork = (0, utils_1.getProtocolNetwork)(chainId);
    const protocol = shared_1.MESSAGING_PROTOCOL_CONFIGS[messagingNetwork];
    if (!protocol.configs[protocol.hub]) {
        throw new Error(`Network ${messagingNetwork} is not supported! (no messaging config)`);
    }
    const connectorName = (0, utils_1.getConnectorName)(protocol, +chainId);
    const connectorManagerDeployment = await hre.deployments.getOrNull((0, utils_1.getDeploymentName)(connectorName, undefined, protocol.configs[Number(chainId)].networkName));
    if (!connectorManagerDeployment) {
        throw new Error(`${connectorName} not deployed`);
    }
    const lpTokenDeployment = await hre.deployments.deploy("LPToken", {
        from: deployer.address,
        log: true,
        skipIfAlreadyDeployed: true,
    });
    if (lpTokenDeployment.newlyDeployed) {
        await hre.deployments.execute("LPToken", { from: deployer.address, log: true }, "initialize", "Connext Stable LP Token", "ConnextStableLPToken");
    }
    // Deploy connext diamond contract
    console.log("Deploying connext diamond...");
    const isDiamondUpgrade = !!(await hre.deployments.getOrNull((0, utils_1.getDeploymentName)("Connext")));
    const facetsToDeploy = [
        {
            // always include the loupe facet
            name: "_DefaultDiamondLoupeFacet",
            contract: "DiamondLoupeFacet",
            args: [],
            deterministic: !zksync,
        },
        { name: (0, utils_1.getDeploymentName)("TokenFacet"), contract: "TokenFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("BridgeFacet"), contract: "BridgeFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("InboxFacet"), contract: "InboxFacet", args: [], deterministic: !zksync },
        {
            name: (0, utils_1.getDeploymentName)("ProposedOwnableFacet"),
            contract: "ProposedOwnableFacet",
            args: [],
            deterministic: !zksync,
        },
        { name: (0, utils_1.getDeploymentName)("PortalFacet"), contract: "PortalFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("RelayerFacet"), contract: "RelayerFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("RoutersFacet"), contract: "RoutersFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("StableSwapFacet"), contract: "StableSwapFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("SwapAdminFacet"), contract: "SwapAdminFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("DiamondCutFacet"), contract: "DiamondCutFacet", args: [], deterministic: !zksync },
        { name: (0, utils_1.getDeploymentName)("DiamondInit"), contract: "DiamondInit", args: [], deterministic: !zksync },
    ];
    // Deploy all the facets
    const facets = [];
    for (const facet of facetsToDeploy) {
        const deployment = await hre.deployments.deploy(facet.name, {
            contract: facet.contract,
            args: facet.args,
            from: deployer.address,
            log: true,
            deterministicDeployment: true,
        });
        facets.push({
            name: facet.name,
            contract: new ethers_1.Contract(deployment.address, deployment.abi),
        });
    }
    let connext;
    if (isDiamondUpgrade) {
        console.log("proposing upgrade...");
        connext = (await hre.deployments.getOrNull((0, utils_1.getDeploymentName)("Connext")));
        const currentConnext = new ethers_1.Contract(connext.address, connext.abi, deployer);
        const cuts = await (0, src_1.getProposedFacetCuts)(facets, currentConnext);
        if (cuts.length) {
            // There is a proposal needed
            console.log(`Proposal needed, proposing upgrade`);
            const proposalTx = await currentConnext.proposeDiamondCut(cuts, ethers_1.constants.AddressZero, "0x");
            console.log(`Proposal tx:`, proposalTx.hash);
            const receipt = await proposalTx.wait();
            console.log(`Upgrade to diamond proposed`, receipt.transactionHash);
        }
        else {
            console.log(`No upgrade needed, using previous deployment`);
        }
        // Fallthrough after proposal, will either work or fail depending on delay
        try {
            if (cuts.length) {
                const contract = new ethers_1.Contract(connext.address, connext.abi, deployer);
                const acceptanceTime = (await contract.getAcceptanceTime(cuts, ethers_1.constants.AddressZero, "0x")).toNumber();
                const currentTimeStamp = Math.floor(Date.now() / 1000);
                if (acceptanceTime > currentTimeStamp) {
                    console.log(`delay not elapsed. still wait for ${acceptanceTime - currentTimeStamp} sec`);
                }
                else {
                    const upgradeTx = await contract.diamondCut(cuts, ethers_1.constants.AddressZero, "0x");
                    console.log("upgrade transaction", upgradeTx.hash);
                    const receipt = await upgradeTx.wait();
                    console.log("upgrade receipt", receipt);
                    // Save updated abi to Connext Deployment if cuts were performed
                    const diamondDeployment = {
                        ...connext,
                        abi: cuts.length ? (0, src_1.getUpgradedAbi)(facets, connext.abi) : connext.abi,
                    };
                    await hre.deployments.save((0, utils_1.getDeploymentName)("Connext"), diamondDeployment);
                    console.log("upgraded abi");
                }
            }
        }
        catch (e) {
            console.log(`upgrade failed`, e);
        }
    }
    else {
        connext = await hre.deployments.diamond.deploy((0, utils_1.getDeploymentName)("Connext"), {
            from: deployer.address,
            owner: deployer.address,
            log: true,
            facets: facetsToDeploy,
            diamondContract: "ConnextDiamond",
            defaultOwnershipFacet: false,
            defaultCutFacet: false,
            execute: isDiamondUpgrade
                ? undefined
                : {
                    contract: "DiamondInit",
                    methodName: "init",
                    args: [domain, connectorManagerDeployment.address, acceptanceDelay, lpTokenDeployment.address],
                },
        });
    }
    const connextAddress = connext.address;
    console.log("connextAddress: ", connextAddress);
    console.log("Deploying Relayer Proxy...");
    const { feeCollector, gelatoRelayer } = (0, utils_1.getRelayerProxyConfig)(chainId);
    const spokeConnector = await hre.ethers.getContract((0, utils_1.getDeploymentName)((0, utils_1.getConnectorName)(protocol, +chainId), undefined, protocol.configs[Number(chainId)].networkName));
    if (protocol.hub === network.chainId) {
        const rootManager = await hre.ethers.getContract((0, utils_1.getDeploymentName)("RootManager"));
        const relayerProxyHub = await hre.deployments.deploy((0, utils_1.getDeploymentName)("RelayerProxyHub"), {
            from: deployer.address,
            log: true,
            contract: "RelayerProxyHub",
            args: [connextAddress, spokeConnector.address, gelatoRelayer, feeCollector, rootManager.address],
        });
        console.log("relayerProxyHub: ", relayerProxyHub.address);
    }
    else {
        const relayerProxy = await hre.deployments.deploy((0, utils_1.getDeploymentName)("RelayerProxy"), {
            from: deployer.address,
            log: true,
            contract: "RelayerProxy",
            args: [connextAddress, spokeConnector.address, gelatoRelayer, feeCollector],
        });
        console.log("relayerProxy: ", relayerProxy.address);
    }
    if (!constants_1.SKIP_SETUP.includes(parseInt(chainId))) {
        console.log("Deploying test token on non-mainnet chain...");
        // Note: NOT using special token for staging envs
        let deployment = await hre.deployments.deploy("TestERC20", {
            from: deployer.address,
            log: true,
            skipIfAlreadyDeployed: true,
            args: ["Test Token", "TEST"],
        });
        console.log("TestERC20: ", deployment.address);
        deployment = await hre.deployments.deploy("TestAdopted", {
            contract: "TestERC20",
            from: deployer.address,
            log: true,
            skipIfAlreadyDeployed: true,
            args: ["Test Adopted", "TEST2"],
        });
        deployment = await hre.deployments.deploy("TestWETH", {
            contract: "TestERC20",
            from: deployer.address,
            log: true,
            skipIfAlreadyDeployed: true,
            args: ["Test Wrapped Ether", "TWETH"],
        });
        console.log("TestERC20: ", deployment.address);
    }
    else {
        console.log("Skipping test setup on chainId: ", chainId);
    }
};
exports.default = func;
func.tags = ["Connext", "prod", "local", "mainnet"];
func.dependencies = ["Messaging"];
//# sourceMappingURL=02_deployConnext.js.map