/**
 * deploy GoodDollar complete protocol from scratch
 */

import { network, ethers, upgrades } from "hardhat";
import { Contract } from "ethers";
import { range } from "lodash";
import DAOCreatorABI from "@gooddollar/goodcontracts/build/contracts/DaoCreatorGoodDollar.json";
import FeeFormulaABI from "@gooddollar/goodcontracts/build/contracts/FeeFormula.json";
import AddFoundersABI from "@gooddollar/goodcontracts/build/contracts/AddFoundersGoodDollar.json";
import ContributionCalculation from "@gooddollar/goodcontracts/stakingModel/build/contracts/ContributionCalculation.json";
import FirstClaimPool from "@gooddollar/goodcontracts/stakingModel/build/contracts/FirstClaimPool.json";
import BridgeMock from "@gooddollar/goodcontracts/stakingModel/build/contracts/BridgeMock.json";
import OTPABI from "@gooddollar/goodcontracts/build/contracts/OneTimePayments.json";
import HomeBridgeABI from "@gooddollar/goodcontracts/build/contracts/DeployHomeBridge.json";
import ForeignBridgeABI from "@gooddollar/goodcontracts/build/contracts/DeployForeignBridge.json";

import releaser from "../scripts/releaser";
import ProtocolSettings from "../releases/deploy-settings.json";
import dao from "../releases/deployment.json";
import { main as deployV2 } from "./upgradeToV2/upgradeToV2";
import { TransactionResponse } from "@ethersproject/providers";
import pressAnyKey from "press-any-key";

const { name } = network;

const printDeploy = async (
  c: Contract | TransactionResponse
): Promise<Contract | TransactionResponse> => {
  if (c instanceof Contract) {
    await c.deployed();
    console.log("deployed to: ", c.address);
  }
  if (c.wait) {
    await c.wait();
    console.log("tx done:", c.hash);
  }
  return c;
};

export const createDAO = async () => {
  const fusedao = dao[network.name.split("-")[0]];
  let release: { [key: string]: any } = {};
  // let release: { [key: string]: any } = dao[network.name];

  let [root, ...signers] = await ethers.getSigners();
  //generic call permissions
  let schemeMock = root;
  const isMainnet = network.name.includes("main");

  console.log("got signers:", {
    network,
    root: root.address,
    schemeMock: schemeMock.address,
    balance: await ethers.provider
      .getBalance(root.address)
      .then(_ => _.toString())
  });

  const DAOCreatorFactory = new ethers.ContractFactory(
    DAOCreatorABI.abi,
    DAOCreatorABI.bytecode,
    root
  );

  // const IdentityFactory = new ethers.ContractFactory(
  //   IdentityABI.abi,
  //   IdentityABI.bytecode,
  //   root
  // );

  const IdentityFactory = await ethers.getContractFactory("IdentityV2");

  const FeeFormulaFactory = new ethers.ContractFactory(
    FeeFormulaABI.abi,
    FeeFormulaABI.bytecode,
    root
  );
  const AddFoundersFactory = new ethers.ContractFactory(
    AddFoundersABI.abi,
    AddFoundersABI.bytecode,
    root
  );

  const BancorFormula = (await (
    await ethers.getContractFactory("BancorFormula")
  )
    .deploy()
    .then(printDeploy)) as Contract;

  await BancorFormula.init()

  const AddFounders = (await AddFoundersFactory.deploy().then(
    printDeploy
  )) as Contract;
  // const AddFounders = await ethers.getContractAt(
  //   AddFoundersABI.abi,
  //   "0x6F1BAbfF5E119d61F0c6d8653d84E8B284B87091"
  // );

  // const Identity = (await IdentityFactory.deploy().then(
  //   printDeploy
  // )) as Contract;

  const Identity = await upgrades.deployProxy(
    IdentityFactory,
    [root.address, ethers.constants.AddressZero],
    { kind: "uups" }
  );
  // const Identity = await ethers.getContractAt(
  //   IdentityABI.abi,
  //   release.Identity
  // );

  const daoCreator = (await DAOCreatorFactory.deploy(AddFounders.address).then(
    printDeploy
  )) as Contract;

  const FeeFormula = (await FeeFormulaFactory.deploy(0).then(
    printDeploy
  )) as Contract;

  // await Identity.setAuthenticationPeriod(365).then(printDeploy);
  // console.log("setAuthPeriod");
  await daoCreator
    .forgeOrg(
      "GoodDollar",
      "G$",
      0,
      FeeFormula.address,
      Identity.address,
      [root.address, signers[0].address, signers[1].address],
      1000,
      [100000, 100000, 100000]
    )
    .then(printDeploy);
  console.log("forgeOrg done ");
  const Avatar = new ethers.Contract(
    await daoCreator.avatar(),
    [
      "function owner() view returns (address)",
      "function nativeToken() view returns (address)"
    ],
    root
  );

  // const Avatar = new ethers.Contract(
  //   release.Avatar,
  //   [
  //     "function owner() view returns (address)",
  //     "function nativeToken() view returns (address)"
  //   ],
  //   root
  // );

  // await Identity.setAvatar(Avatar.address).then(printDeploy);

  console.log("Done deploying DAO, setting schemes permissions");

  let schemes = [schemeMock.address, Identity.address];

  const gd = await Avatar.nativeToken();

  const controller = await Avatar.owner();

  console.log("setting schemes", schemes);

  await daoCreator
    .setSchemes(
      Avatar.address,
      schemes,
      schemes.map(_ => ethers.constants.HashZero),
      ["0x0000001F", "0x00000001"],
      ""
    )
    .then(printDeploy);

  let { setSchemes, genericCall, addWhitelisted } = await getHelperFunctions(
    Identity,
    Avatar,
    schemeMock
  );

  let mainnet: { [key: string]: Contract } = {};
  release = {
    ...release,
    Avatar: Avatar.address,
    Controller: controller,
    GoodDollar: gd,
    Identity: Identity.address,
    FeeFormula: FeeFormula.address,
    BancorFormula: BancorFormula.address
  };

  if (isMainnet) {
    mainnet = await deployMainnet(Avatar, Identity);
    Object.entries(mainnet)
      .filter(([k, v]) => v)
      .forEach(([k, v]) => (release[k] = v.address));
  }

  let sidechain: { [key: string]: any } = {};

  if (false === isMainnet) {
    sidechain = await deploySidechain(
      setSchemes,
      genericCall,
      Avatar.address,
      Identity.address,
      gd
    );
    schemes.push(sidechain.OneTimePayments.address);
    Object.entries(sidechain).forEach(([k, v]) => (release[k] = v.address));
  }

  await releaser(release, network.name);

  const bridgeRelease = await deployBridge(Avatar, gd, setSchemes, isMainnet);
  release = { ...release, ...bridgeRelease };
  await releaser(release, network.name);

  // await pressAnyKey();
  // deploy v2 mainnet/sidechain contracts, returns their addresses
  const olddao = {
    FirstClaimPool: release.FirstClaimPool,
    BancorFormula: release.BancorFormula,
    Avatar: release.Avatar,
    Controller: release.Controller,
    DAIUsdOracle: release.DAIUsdOracle,
    COMPUsdOracle: release.COMPUsdOracle,
    USDCUsdOracle: release.USDCUsdOracle,
    AAVEUsdOracle: release.AAVEUsdOracle,
    AaveLendingPool: null,
    AaveIncentiveController: null,
    GasPriceOracle: release.GasPriceOracle,
    cDAI: release.cDAI || ethers.constants.AddressZero,
    DAI: release.DAI || ethers.constants.AddressZero,
    COMP: release.COMP || ethers.constants.AddressZero,
    USDC: ethers.constants.AddressZero,
    DAIEthOracle: release.DAIEthOracle || ethers.constants.AddressZero,
    ETHUsdOracle: release.ETHUsdOracle || ethers.constants.AddressZero,
    Identity: release.Identity,
    GoodDollar: release.GoodDollar,
    Contribution: release.Contribution,
    UniswapRouter: "0x0000000000000000000000000000000000000001",
    HomeBridge: release.HomeBridge,
    ForeignBridge: release.ForeignBridge,
    SchemeRegistrar: ethers.constants.AddressZero,
    UpgradeScheme: ethers.constants.AddressZero
  };

  console.log("deploying v2...");
  const v2 = await deployV2(network.name, false, olddao);
  if (isMainnet) {
    let distHelper = await upgrades.deployProxy(
      await ethers.getContractFactory("DistributionHelper"),
      [v2.NameService],
      {
        initializer: "initialize(address)",
        kind: "uups"
      }
    );

    const goodReserve = await ethers.getContractFactory("GoodReserveCDai");
    console.log("setting distribution helper...");

    await genericCall(
      v2.GoodReserveCDai,
      goodReserve.interface.encodeFunctionData("setDistributionHelper", [
        distHelper.address
      ])
    );
  }
  console.log("deploying adminWallet...");
  const adminWallet = await deployAdminWallet(Identity.address, v2.NameService);
  console.log("setting up identity:", {
    ns: v2.NameService,
    identity: Identity.address
  });
  await Identity.initDAO(v2.NameService);
  release["AdminWallet"] = adminWallet.address;

  release = { ...v2, ...release };
  await releaser(release, network.name);
  // await pressAnyKey();
  if (isMainnet) {
    await setSchemes([release.ProtocolUpgrade]);
    await performUpgrade(release, fusedao.UBIScheme);

    console.log("setting reserve token");
    const MarketMaker = await ethers.getContractFactory("GoodMarketMaker");
    let encoded = MarketMaker.interface.encodeFunctionData("initializeToken", [
      release.cDAI,
      "100",
      "10000",
      "1000000",
      "0"
    ]);

    await genericCall(release.GoodMarketMaker, encoded);
  }

  if (false === isMainnet) {
    let encoded = (
      await ethers.getContractAt("IGoodDollar", release.GoodDollar)
    ).interface.encodeFunctionData("mint", [release.UBIScheme, 1000000]);

    await genericCall(release.GoodDollar, encoded);

    await setSchemes([release.ProtocolUpgradeFuse]);
    await performUpgradeFuse(release);
  }

  await releaser(release, network.name);
};

const deployBridge = async (Avatar, gd, setSchemes, isMainnet) => {
  const GoodDollar = await ethers.getContractAt("IGoodDollar", gd);
  const [root] = await ethers.getSigners();
  const BridgeABI = isMainnet ? ForeignBridgeABI : HomeBridgeABI;
  const bridgeFactory = new ethers.ContractFactory(
    BridgeABI.abi,
    BridgeABI.bytecode,
    root
  );
  let BridgeFactoryContract = isMainnet
    ? "0xABBf5D8599B2Eb7b4e1D25a1Fd737FF1987655aD"
    : "0xb895638fb3870AD5832402a5BcAa64A044687db0"; //Fuse test bridge addresses

  const isAlreadyMinter = await GoodDollar.isMinter(BridgeFactoryContract);
  console.log("deploying bridge scheme:", {
    BridgeFactoryContract,
    isMainnet,
    isAlreadyMinter
  });
  const scheme = (await bridgeFactory
    .deploy(Avatar.address, BridgeFactoryContract)
    .then(printDeploy)) as Contract;
  await setSchemes([scheme.address]);

  if (network.name.includes("develop") || network.name.includes("dapptest")) {
    const mockBridge = (await new ethers.ContractFactory(
      BridgeMock.abi,
      BridgeMock.bytecode,
      root
    )
      .deploy()
      .then(printDeploy)) as Contract;
    console.log("deployed mock bridge for develop mode:", mockBridge.address);
    return isMainnet
      ? { ForeignBridge: mockBridge.address }
      : { HomeBridge: mockBridge.address };
  }

  let tx = await (
    await (isMainnet
      ? scheme.setBridge()
      : scheme.setBridge(isAlreadyMinter === false))
  ).wait();
  const bridgeEvent = tx.events.find(_ => _.event?.includes("Bridge"));
  console.log("deployed bridge:", bridgeEvent);
  console.log(tx.events, tx);
  return isMainnet
    ? { ForeignBridge: bridgeEvent.args._foreignBridge }
    : { HomeBridge: bridgeEvent.args._homeBridge };
};

const deployMainnet = async (Avatar, Identity) => {
  console.log("deploying mainnet...");

  const [root] = await ethers.getSigners();

  const cdaiFactory = await ethers.getContractFactory("cDAIMock");
  const daiFactory = await ethers.getContractFactory("DAIMock");

  const daiAddr = ProtocolSettings[network.name]?.compound?.dai;
  const cdaiAddr = ProtocolSettings[network.name]?.compound?.cdai;
  const COMPAddr = ProtocolSettings[network.name]?.compound?.comp;
  const daiEthOracleAddr = ProtocolSettings[network.name]?.chainlink?.dai_eth;
  const ethUsdOracleAddr = ProtocolSettings[network.name]?.chainlink?.eth_usd;

  let DAIUsdOracle, COMPUsdOracle, USDCUsdOracle, AAVEUsdOracle, GasPriceOracle;
  if (name.includes("test")) {
    const tokenUsdOracleFactory = await ethers.getContractFactory(
      "BatUSDMockOracle"
    );
    DAIUsdOracle = await tokenUsdOracleFactory.deploy();
    USDCUsdOracle = await tokenUsdOracleFactory.deploy();

    COMPUsdOracle = await (
      await ethers.getContractFactory("CompUSDMockOracle")
    ).deploy();
    AAVEUsdOracle = await (
      await ethers.getContractFactory("AaveUSDMockOracle")
    ).deploy();
    GasPriceOracle = await (
      await ethers.getContractFactory("GasPriceMockOracle")
    ).deploy();
  }

  let DAI = daiAddr
    ? await ethers.getContractAt("DAIMock", daiAddr)
    : ((await daiFactory.deploy().then(printDeploy)) as Contract);

  let COMP = COMPAddr
    ? await ethers.getContractAt("DAIMock", COMPAddr)
    : ((await daiFactory.deploy().then(printDeploy)) as Contract);

  let cDAI = cdaiAddr
    ? await ethers.getContractAt("DAIMock", cdaiAddr)
    : ((await cdaiFactory.deploy(DAI.address).then(printDeploy)) as Contract);

  const ccFactory = new ethers.ContractFactory(
    ContributionCalculation.abi,
    ContributionCalculation.bytecode,
    root
  );

  const Contribution = (await ccFactory
    .deploy(Avatar.address, 0, 1e15)
    .then(printDeploy)) as Contract;

  let DAIEthOracle = daiEthOracleAddr
    ? await ethers.getContractAt("DaiEthPriceMockOracle", daiEthOracleAddr)
    : ((await (await ethers.getContractFactory("DaiEthPriceMockOracle"))
      .deploy()
      .then(printDeploy)) as Contract);

  let ETHUsdOracle = ethUsdOracleAddr
    ? await ethers.getContractAt("EthUSDMockOracle", ethUsdOracleAddr)
    : ((await (await ethers.getContractFactory("EthUSDMockOracle"))
      .deploy()
      .then(printDeploy)) as Contract);

  return {
    Contribution,
    DAI,
    COMP,
    cDAI,
    ETHUsdOracle,
    DAIEthOracle,
    DAIUsdOracle,
    COMPUsdOracle,
    USDCUsdOracle,
    AAVEUsdOracle,
    GasPriceOracle
  };
};

export const deploySidechain = async (
  setSchemes,
  genericCall,
  avatar,
  identity,
  gd
) => {
  console.log("deploying sidechain...");
  const root = (await ethers.getSigners())[0];
  const fcFactory = new ethers.ContractFactory(
    FirstClaimPool.abi,
    FirstClaimPool.bytecode,
    root
  );
  const otpf = await new ethers.ContractFactory(
    OTPABI.abi,
    OTPABI.bytecode,
    root
  );

  //   const invitesf = await new ethers.ContractFactory(
  //     InvitesABI.abi,
  //     InvitesABI.bytecode,
  //     root
  //   );

  const invitesf = await ethers.getContractFactory("InvitesV1");
  const faucetf = await ethers.getContractFactory("FuseFaucet");

  //   const faucetf = await new ethers.ContractFactory(
  //     FaucetABI.abi,
  //     FaucetABI.bytecode,
  //     root
  //   );

  console.log("deploying first claim...", {
    avatar,
    identity
  });

  const firstClaim = (await fcFactory
    .deploy(avatar, identity, 1000)
    .then(printDeploy)) as Contract;

  let encoded = (
    await ethers.getContractAt("IGoodDollar", gd)
  ).interface.encodeFunctionData("mint", [firstClaim.address, 1000000]);

  await genericCall(gd, encoded);

  console.log("deploying OneTimePayments");

  const otp = (await otpf
    .deploy(avatar, identity)
    .then(printDeploy)) as Contract;

  console.log("deploying OneTimePayments invites");
  const invites = (await upgrades
    .deployProxy(invitesf, [avatar, identity, gd, 10000])
    .then(printDeploy)) as Contract;

  const faucet = (await upgrades
    .deployProxy(faucetf, [identity])
    .then(printDeploy)) as Contract;

  await root
    .sendTransaction({
      to: faucet.address,
      value: ethers.utils.parseEther("5")
    })
    .then(printDeploy);

  encoded = (
    await ethers.getContractAt("IGoodDollar", gd)
  ).interface.encodeFunctionData("mint", [firstClaim.address, 1000000]);
  await genericCall(gd, encoded);

  encoded = (
    await ethers.getContractAt("IGoodDollar", gd)
  ).interface.encodeFunctionData("mint", [invites.address, 1000000]);

  await genericCall(gd, encoded);

  console.log("setting firstclaim and otp schemes...");
  await setSchemes([firstClaim.address, otp.address]);
  await firstClaim.start().then(printDeploy);

  return {
    FirstClaimPool: firstClaim,
    OneTimePayments: otp,
    Invites: invites,
    FuseFaucet: faucet
  };
};

const deployAdminWallet = async (identity, ns) => {
  const root = (await ethers.getSigners())[0];
  const hdNode = ethers.utils.HDNode.fromMnemonic(process.env.ADMIN_MNEMONIC);
  const admins = range(0, 50).map(i =>
    hdNode.derivePath(`m/44'/60'/0'/0/${i}`)
  );

  const adminWallet = (await upgrades
    .deployProxy(await ethers.getContractFactory("AdminWallet"), [
      admins.slice(0, 20).map(_ => _.address),
      ns,
      root.address,
      1e9
    ])
    .then(printDeploy)) as Contract;

  // const adminWallet = (await new ethers.ContractFactory(
  //   AdminWalletABI.abi,
  //   AdminWalletABI.bytecode,
  //   root
  // )
  //   .deploy(
  //     admins.slice(0, 20).map(_ => _.address),
  //     ethers.utils.parseUnits("1000000", "gwei"),
  //     4,
  //     identity
  //   )
  //   .then(printDeploy)) as Contract;

  const id = await ethers.getContractAt("IdentityV2", identity);
  await id
    .grantRole(await id.IDENTITY_ADMIN_ROLE(), adminWallet.address)
    .then(printDeploy);
  await root
    .sendTransaction({
      to: adminWallet.address,
      value: ethers.utils.parseEther("1")
    })
    .then(printDeploy);
  await adminWallet["topAdmins(uint256)"](0).then(printDeploy);
  console.log(
    "deployAdminWallet admins:",
    admins.map(_ => _.address),
    "balance:",
    await ethers.provider.getBalance(adminWallet.address)
  );

  return adminWallet;
};

const getHelperFunctions = async (Identity, Avatar, schemeMock) => {
  const controller = await Avatar.owner();
  const Controller = await ethers.getContractAt(
    "Controller",
    controller,
    schemeMock
  );
  const setSchemes = async (addrs, params = []) => {
    for (let i in addrs) {
      await Controller.registerScheme(
        addrs[i],
        params[i] || ethers.constants.HashZero,
        "0x0000001F",
        Avatar.address
      ).then(printDeploy);
    }
  };

  const genericCall = (target, encodedFunc) => {
    return Controller.genericCall(target, encodedFunc, Avatar.address, 0).then(
      printDeploy
    );
  };

  const addWhitelisted = (addr, did, isContract = false) => {
    if (isContract) return Identity.addContract(addr);
    return Identity.addWhitelistedWithDID(addr, did).then(printDeploy);
  };

  return { setSchemes, addWhitelisted, genericCall };
};

const performUpgradeFuse = async release => {
  const upgrade = await ethers.getContractAt(
    "ProtocolUpgradeFuse",
    release.ProtocolUpgradeFuse
  );

  console.log("performing protocol v2 upgrade on Fuse...", { release });
  await upgrade
    .upgrade(
      release.NameService,
      //old contracts
      [
        ethers.constants.AddressZero,
        ethers.constants.AddressZero,
        ethers.constants.AddressZero,
        release.FirstClaimPool
      ],
      release.UBIScheme,
      [
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("REPUTATION")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("BRIDGE_CONTRACT")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("UBISCHEME")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("GDAO_STAKING")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("GDAO_CLAIMERS"))
      ],
      [
        release.GReputation,
        release.HomeBridge || ethers.constants.AddressZero,
        release.UBIScheme,
        release.GovernanceStaking,
        release.ClaimersDistribution
      ]
    )
    .then(printDeploy);

  console.log("upgrading governance...");

  await upgrade
    .upgradeGovernance(
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      release.CompoundVotingMachine
    )
    .then(printDeploy);
};

const performUpgrade = async (release, ubiScheme) => {
  const upgrade = await ethers.getContractAt(
    "ProtocolUpgrade",
    release.ProtocolUpgrade
  );

  console.log("performing protocol v2 upgrade on Mainnet...", {
    release
  });
  console.log(
    "upgrading nameservice + staking rewards...",
    release.NameService,
    [
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("RESERVE")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("MARKET_MAKER")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("FUND_MANAGER")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("REPUTATION")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("GDAO_STAKERS")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("BRIDGE_CONTRACT")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("UBI_RECIPIENT")),
      ethers.utils.keccak256(ethers.utils.toUtf8Bytes("EXCHANGE_HELPER"))
    ],
    [
      release.GoodReserveCDai,
      release.GoodMarketMaker,
      release.GoodFundManager,
      release.GReputation,
      release.StakersDistribution,
      release.ForeignBridge || ethers.constants.AddressZero,
      ubiScheme,
      release.ExchangeHelper
    ],
    release.StakingContracts.map((_: any) => _[0]),
    release.StakingContracts.map((_: any) => _[1])
  );
  let tx;
  tx = await upgrade
    .upgradeBasic(
      release.NameService,
      [
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("RESERVE")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("MARKET_MAKER")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("FUND_MANAGER")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("REPUTATION")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("GDAO_STAKERS")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("BRIDGE_CONTRACT")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("UBI_RECIPIENT")),
        ethers.utils.keccak256(ethers.utils.toUtf8Bytes("EXCHANGE_HELPER"))
      ],
      [
        release.GoodReserveCDai,
        release.GoodMarketMaker,
        release.GoodFundManager,
        release.GReputation,
        release.StakersDistribution,
        release.ForeignBridge || ethers.constants.AddressZero,
        ubiScheme,
        release.ExchangeHelper
      ],
      release.StakingContracts.map((_: any) => _[0]),
      release.StakingContracts.map((_: any) => _[1])
    )
    .then(printDeploy);

  console.log("upgrading reserve...", {
    params: [
      release.NameService,
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      release.COMP
    ]
  });
  tx = await upgrade
    .upgradeReserve(
      release.NameService,
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      release.COMP
    )
    .then(printDeploy);

  console.log("upgrading governance...");

  tx = await upgrade
    .upgradeGovernance(
      ethers.constants.AddressZero,
      ethers.constants.AddressZero,
      release.CompoundVotingMachine
    )
    .then(printDeploy);
};

const main = async () => {
  await createDAO();
};
main().catch(e => console.log(e));
