diff --git a/contracts/multisigs/endowment-multisig/scripts/deploy.ts b/contracts/multisigs/endowment-multisig/scripts/deploy.ts index 1fe98515e..3f88eaab7 100644 --- a/contracts/multisigs/endowment-multisig/scripts/deploy.ts +++ b/contracts/multisigs/endowment-multisig/scripts/deploy.ts @@ -1,73 +1,3 @@ -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {HardhatRuntimeEnvironment} from "hardhat/types"; -import { - EndowmentMultiSigEmitter__factory, - EndowmentMultiSigFactory__factory, - EndowmentMultiSig__factory, -} from "typechain-types"; -import {Deployment, ProxyDeployment} from "types"; -import {deploy, deployBehindProxy, logger, updateAddresses} from "utils"; - -export async function deployEndowmentMultiSig( - registrar: string, - proxyAdmin: string, - factoryOwner: string, - deployer: SignerWithAddress, - hre: HardhatRuntimeEnvironment -): Promise<{ - emitter: ProxyDeployment; - factory: Deployment; - implementation: Deployment; -}> { - logger.out("Deploying EndowmentMultiSig contracts..."); - - // deploy implementation contract - const implementation = await deploy(new EndowmentMultiSig__factory(deployer)); - - // deploy factory - const factory = await deploy(new EndowmentMultiSigFactory__factory(deployer), [ - implementation.contract.address, - proxyAdmin, - registrar, - ]); - - logger.out(`Transferring ownership to: ${factoryOwner}...`); - const tx = await factory.contract.transferOwnership(factoryOwner); - logger.out(`Tx hash: ${tx.hash}`); - await tx.wait(); - const newOwner = await factory.contract.owner(); - if (newOwner !== factoryOwner) { - throw new Error(`Error updating owner: expected '${factoryOwner}', actual: '${newOwner}'`); - } - - // emitter data setup - const Emitter = new EndowmentMultiSigEmitter__factory(deployer); - const initData = Emitter.interface.encodeFunctionData("initEndowmentMultiSigEmitter", [ - factory.contract.address, - ]); - // deploy emitter - const emitter = await deployBehindProxy(Emitter, proxyAdmin, initData); - - // update address file - await updateAddresses( - { - multiSig: { - endowment: { - emitter: { - implementation: emitter.implementation.contract.address, - proxy: emitter.proxy.contract.address, - }, - factory: factory.contract.address, - implementation: implementation.contract.address, - }, - }, - }, - hre - ); - - return { - emitter, - factory, - implementation, - }; -} +export * from "./deployEndowmentMultiSig"; +export * from "./deployEndowmentMultiSigEmitter"; +export * from "./deployEndowmentMultiSigFactory"; diff --git a/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSig.ts b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSig.ts new file mode 100644 index 000000000..b3ba5ed18 --- /dev/null +++ b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSig.ts @@ -0,0 +1,29 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {EndowmentMultiSig__factory} from "typechain-types"; +import {Deployment} from "types"; +import {deploy, logger, updateAddresses} from "utils"; + +export async function deployEndowmentMultiSig( + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise> { + logger.out("Deploying EndowmentMultiSig..."); + + // deploy implementation contract + const implementation = await deploy(new EndowmentMultiSig__factory(deployer)); + + // update address file + await updateAddresses( + { + multiSig: { + endowment: { + implementation: implementation.contract.address, + }, + }, + }, + hre + ); + + return implementation; +} diff --git a/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigEmitter.ts b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigEmitter.ts new file mode 100644 index 000000000..2107cd528 --- /dev/null +++ b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigEmitter.ts @@ -0,0 +1,36 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {EndowmentMultiSigEmitter__factory} from "typechain-types"; +import {ProxyDeployment} from "types"; +import {deployBehindProxy, logger, updateAddresses} from "utils"; + +export async function deployEndowmentMultiSigEmitter( + factory: string, + proxyAdmin: string, + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise> { + logger.out("Deploying EndowmentMultiSigEmitter..."); + + // deploy emitter + const Emitter = new EndowmentMultiSigEmitter__factory(deployer); + const initData = Emitter.interface.encodeFunctionData("initEndowmentMultiSigEmitter", [factory]); + const emitter = await deployBehindProxy(Emitter, proxyAdmin, initData); + + // update address file + await updateAddresses( + { + multiSig: { + endowment: { + emitter: { + implementation: emitter.implementation.contract.address, + proxy: emitter.proxy.contract.address, + }, + }, + }, + }, + hre + ); + + return emitter; +} diff --git a/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigFactory.ts b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigFactory.ts new file mode 100644 index 000000000..34c22a802 --- /dev/null +++ b/contracts/multisigs/endowment-multisig/scripts/deployEndowmentMultiSigFactory.ts @@ -0,0 +1,46 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {EndowmentMultiSigFactory__factory} from "typechain-types"; +import {Deployment} from "types"; +import {deploy, logger, updateAddresses} from "utils"; + +export async function deployEndowmentMultiSigFactory( + implementation: string, + registrar: string, + proxyAdmin: string, + factoryOwner: string, + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise> { + logger.out("Deploying EndowmentMultiSigFactory..."); + + // deploy factory + const factory = await deploy(new EndowmentMultiSigFactory__factory(deployer), [ + implementation, + proxyAdmin, + registrar, + ]); + + logger.out(`Transferring ownership to: ${factoryOwner}...`); + const tx = await factory.contract.transferOwnership(factoryOwner); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + const newOwner = await factory.contract.owner(); + if (newOwner !== factoryOwner) { + throw new Error(`Error updating owner: expected '${factoryOwner}', actual: '${newOwner}'`); + } + + // update address file + await updateAddresses( + { + multiSig: { + endowment: { + factory: factory.contract.address, + }, + }, + }, + hre + ); + + return factory; +} diff --git a/tasks/deploy/deployAngelProtocol.ts b/tasks/deploy/deployAngelProtocol.ts index eb5809cb5..c6c7b85c2 100644 --- a/tasks/deploy/deployAngelProtocol.ts +++ b/tasks/deploy/deployAngelProtocol.ts @@ -5,7 +5,11 @@ import {deployIndexFund} from "contracts/core/index-fund/scripts/deploy"; import {deployRegistrar} from "contracts/core/registrar/scripts/deploy"; import {deployRouter} from "contracts/core/router/scripts/deploy"; import {deployVaultEmitter} from "contracts/core/vault/scripts/deployVaultEmitter"; -import {deployEndowmentMultiSig} from "contracts/multisigs/endowment-multisig/scripts/deploy"; +import { + deployEndowmentMultiSig, + deployEndowmentMultiSigEmitter, + deployEndowmentMultiSigFactory, +} from "contracts/multisigs/endowment-multisig/scripts/deploy"; import { deployAPTeamMultiSig, deployCharityApplications, @@ -132,13 +136,21 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") hre ); - const endowmentMultiSig = await deployEndowmentMultiSig( + const endowmentMultiSig = await deployEndowmentMultiSig(deployer, hre); + const endowmentMultiSigFactory = await deployEndowmentMultiSigFactory( + endowmentMultiSig.contract.address, registrar.proxy.contract.address, proxyAdminMultisig.contract.address, apTeamMultisig.proxy.contract.address, deployer, hre ); + const endowmentMultiSigEmitter = await deployEndowmentMultiSigEmitter( + endowmentMultiSigFactory.contract.address, + proxyAdminMultisig.contract.address, + deployer, + hre + ); const vaultEmitter = await deployVaultEmitter( proxyAdminMultisig.contract.address, @@ -152,8 +164,8 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") treasury: treasuryAddress, uniswapRouter: thirdPartyAddresses.uniswap.swapRouter.address, //address uniswapFactory: thirdPartyAddresses.uniswap.factory.address, //address - multisigFactory: endowmentMultiSig.factory.contract.address, //address - multisigEmitter: endowmentMultiSig.emitter.proxy.contract.address, //address + multisigFactory: endowmentMultiSigFactory.contract.address, //address + multisigEmitter: endowmentMultiSigEmitter.proxy.contract.address, //address charityApplications: charityApplications.proxy.contract.address, //address proxyAdmin: proxyAdminMultisig.contract.address, //address usdcAddress: thirdPartyAddresses.usdcToken.address, @@ -187,10 +199,10 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") charityApplications.proxy, indexFund.implementation, indexFund.proxy, - endowmentMultiSig.emitter.implementation, - endowmentMultiSig.emitter.proxy, - endowmentMultiSig.factory, - endowmentMultiSig.implementation, + endowmentMultiSigEmitter.implementation, + endowmentMultiSigEmitter.proxy, + endowmentMultiSigFactory, + endowmentMultiSig, gasFwd.factory, gasFwd.implementation, vaultEmitter.implementation, diff --git a/tasks/deploy/deployEndowmentMultisig.ts b/tasks/deploy/deployEndowmentMultisig.ts index 092ae848e..4953eac0d 100644 --- a/tasks/deploy/deployEndowmentMultisig.ts +++ b/tasks/deploy/deployEndowmentMultisig.ts @@ -1,57 +1,31 @@ import {deployEndowmentMultiSig} from "contracts/multisigs/endowment-multisig/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, isLocalNetwork, getAddresses, logger, verify, getSigners} from "utils"; +import {confirmAction, getSigners, isLocalNetwork, logger, verify} from "utils"; type TaskArgs = { - apTeamSignerPkey?: string; - registrar?: string; skipVerify: boolean; yes: boolean; }; task("deploy:EndowmentMultiSig", "Will deploy EndowmentMultiSig contract") - .addOptionalParam( - "registrar", - "Addresss of the registrar contract. Will do a local lookup from contract-address.json if none is provided." - ) - .addOptionalParam( - "apTeamSignerPkey", - "If running on prod, provide a pkey for a valid APTeam Multisig Owner." - ) .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { - const addresses = await getAddresses(hre); - const {deployer} = await getSigners(hre); + logger.divider(); + logger.out("Deploying EndowmentMultiSig..."); - const registrarAddress = taskArgs.registrar || addresses.registrar.proxy; + const {deployer} = await getSigners(hre); - const isConfirmed = taskArgs.yes || (await confirmAction("Deploying EndowmentMultiSig...")); + const isConfirmed = taskArgs.yes || (await confirmAction()); if (!isConfirmed) { return logger.out("Confirmation denied.", logger.Level.Warn); } - const deployData = await deployEndowmentMultiSig( - registrarAddress, - addresses.multiSig.proxyAdmin, - addresses.multiSig.apTeam.proxy, - deployer, - hre - ); - - await hre.run("manage:registrar:updateConfig", { - multisigFactory: deployData.factory.contract.address, - multisigEmitter: deployData.emitter.proxy.contract.address, - apTeamSignerPkey: taskArgs.apTeamSignerPkey, - yes: true, - }); + const deployData = await deployEndowmentMultiSig(deployer, hre); if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { - await verify(hre, deployData.emitter.implementation); - await verify(hre, deployData.emitter.proxy); - await verify(hre, deployData.factory); - await verify(hre, deployData.implementation); + await verify(hre, deployData); } } catch (error) { logger.out(error, logger.Level.Error); diff --git a/tasks/deploy/deployEndowmentMultisigEmitter.ts b/tasks/deploy/deployEndowmentMultisigEmitter.ts new file mode 100644 index 000000000..26eb3f43f --- /dev/null +++ b/tasks/deploy/deployEndowmentMultisigEmitter.ts @@ -0,0 +1,51 @@ +import {deployEndowmentMultiSigEmitter} from "contracts/multisigs/endowment-multisig/scripts/deploy"; +import {task} from "hardhat/config"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; + +type TaskArgs = { + apTeamSignerPkey?: string; + skipVerify: boolean; + yes: boolean; +}; + +task("deploy:EndowmentMultiSigEmitter", "Will deploy EndowmentMultiSigEmitter contract") + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: TaskArgs, hre) => { + try { + logger.divider(); + logger.out("Deploying EndowmentMultiSigEmitter..."); + + const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); + + const isConfirmed = taskArgs.yes || (await confirmAction()); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const deployData = await deployEndowmentMultiSigEmitter( + addresses.multiSig.endowment.factory, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); + + await hre.run("manage:registrar:updateConfig", { + multisigEmitter: deployData.proxy.contract.address, + apTeamSignerPkey: taskArgs.apTeamSignerPkey, + yes: true, + }); + + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, deployData.implementation); + await verify(hre, deployData.proxy); + } + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/tasks/deploy/deployEndowmentMultisigFactory.ts b/tasks/deploy/deployEndowmentMultisigFactory.ts new file mode 100644 index 000000000..f55a5b53b --- /dev/null +++ b/tasks/deploy/deployEndowmentMultisigFactory.ts @@ -0,0 +1,52 @@ +import {deployEndowmentMultiSigFactory} from "contracts/multisigs/endowment-multisig/scripts/deploy"; +import {task} from "hardhat/config"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; + +type TaskArgs = { + apTeamSignerPkey?: string; + skipVerify: boolean; + yes: boolean; +}; + +task("deploy:EndowmentMultiSigFactory", "Will deploy EndowmentMultiSigFactory contract") + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: TaskArgs, hre) => { + try { + logger.divider(); + logger.out("Deploying EndowmentMultiSigFactory..."); + + const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); + + const isConfirmed = taskArgs.yes || (await confirmAction()); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const deployData = await deployEndowmentMultiSigFactory( + addresses.multiSig.endowment.implementation, + addresses.registrar.proxy, + addresses.multiSig.proxyAdmin, + addresses.multiSig.apTeam.proxy, + deployer, + hre + ); + + await hre.run("manage:registrar:updateConfig", { + multisigFactory: deployData.contract.address, + apTeamSignerPkey: taskArgs.apTeamSignerPkey, + yes: true, + }); + + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, deployData); + } + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/tasks/deploy/index.ts b/tasks/deploy/index.ts index b65b3ca31..adbfc18df 100644 --- a/tasks/deploy/index.ts +++ b/tasks/deploy/index.ts @@ -4,6 +4,8 @@ import "./deployAccountsDiamond"; import "./deployAngelProtocol"; import "./deployCharityApplications"; import "./deployEndowmentMultisig"; +import "./deployEndowmentMultisigEmitter"; +import "./deployEndowmentMultisigFactory"; import "./deployGasFwd"; // import "./deployGiftcard"; import "./deployHaloImplementation"; diff --git a/tasks/helpers/submitMultiSigTx.ts b/tasks/helpers/submitMultiSigTx.ts index 2be3a868c..e8f2956cb 100644 --- a/tasks/helpers/submitMultiSigTx.ts +++ b/tasks/helpers/submitMultiSigTx.ts @@ -1,6 +1,5 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {BytesLike, Wallet} from "ethers"; -import {parseUnits} from "ethers/lib/utils"; import {IMultiSigGeneric__factory} from "typechain-types"; import {filterEvents, logger} from "utils"; @@ -33,6 +32,7 @@ export async function submitMultiSigTx( multisig.filters.TransactionExecuted() ).at(0); if (transactionExecutedEvent) { + logger.out("Tx executed."); return true; } @@ -54,7 +54,7 @@ export async function submitMultiSigTx( } // is confirmed but not executed -> requires manual execution - logger.out(`Executing the new charity endowment with transaction ID: ${txId}...`); + logger.out(`Manual execution required, executing transaction: ${txId}...`); const tx2 = await multisig.executeTransaction(txId); logger.out(`Tx hash: ${tx2.hash}`); const execReceipt = await tx2.wait(); @@ -68,5 +68,6 @@ export async function submitMultiSigTx( throw new Error(`Unexpected: ${multisig.filters.TransactionExecuted.name} not emitted.`); } + logger.out("Tx executed."); return true; } diff --git a/tasks/upgrade/endowmentMultiSig/index.ts b/tasks/upgrade/endowmentMultiSig/index.ts deleted file mode 100644 index 6b6aaacc4..000000000 --- a/tasks/upgrade/endowmentMultiSig/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import "./upgradeEmitter"; -import "./upgradeImplementation"; diff --git a/tasks/upgrade/index.ts b/tasks/upgrade/index.ts index 97ed41661..0335644d7 100644 --- a/tasks/upgrade/index.ts +++ b/tasks/upgrade/index.ts @@ -1,7 +1,9 @@ -import "./endowmentMultiSig"; import "./upgradeAPTeamMultiSig"; import "./upgradeCharityApplications"; import "./upgradeContractsUsingAccountStorage"; import "./upgradeFacets"; +import "./upgradeEndowmentMultiSig"; +import "./upgradeEndowmentMultiSigEmitter"; import "./upgradeRegistrar"; import "./upgradeRouter"; +import "./upgradeVaultEmitter"; diff --git a/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts b/tasks/upgrade/upgradeEndowmentMultiSig.ts similarity index 98% rename from tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts rename to tasks/upgrade/upgradeEndowmentMultiSig.ts index b383de960..40c74f8ab 100644 --- a/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts +++ b/tasks/upgrade/upgradeEndowmentMultiSig.ts @@ -21,7 +21,7 @@ type TaskArgs = { }; task( - "upgrade:endowmentMultiSig:implementation", + "upgrade:EndowmentMultiSig", "Will upgrade the implementation of the EndowmentMultiSig contract" ) .addOptionalParam( diff --git a/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts b/tasks/upgrade/upgradeEndowmentMultiSigEmitter.ts similarity index 98% rename from tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts rename to tasks/upgrade/upgradeEndowmentMultiSigEmitter.ts index 8db8137d6..455cefab7 100644 --- a/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts +++ b/tasks/upgrade/upgradeEndowmentMultiSigEmitter.ts @@ -24,7 +24,7 @@ type TaskArgs = { }; task( - "upgrade:endowmentMultiSig:emitter", + "upgrade:EndowmentMultiSigEmitter", "Will upgrade the EndowmentMultiSigEmitter implementation contract" ) .addFlag("skipVerify", "Skip contract verification") diff --git a/tasks/upgrade/upgradeVaultEmitter.ts b/tasks/upgrade/upgradeVaultEmitter.ts new file mode 100644 index 000000000..02a735421 --- /dev/null +++ b/tasks/upgrade/upgradeVaultEmitter.ts @@ -0,0 +1,62 @@ +import {task} from "hardhat/config"; +import {VaultEmitter__factory} from "typechain-types"; +import { + confirmAction, + getAddresses, + getProxyAdminOwner, + getSigners, + isLocalNetwork, + logger, + updateAddresses, + upgradeProxy, + verify, +} from "utils"; + +type TaskArgs = { + proxyAdminPkey?: string; + skipVerify: boolean; + yes: boolean; +}; + +task("upgrade:VaultEmitter", "Will upgrade the implementation of the VaultEmitter contract") + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") + .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") + .setAction(async (taskArgs: TaskArgs, hre) => { + try { + logger.divider(); + logger.out("Upgrading VaultEmitter proxy contract..."); + + const isConfirmed = taskArgs.yes || (await confirmAction()); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } + + const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); + + const proxyAdminOwner = await getProxyAdminOwner(hre, taskArgs.proxyAdminPkey); + + const deployment = await upgradeProxy( + new VaultEmitter__factory(deployer), + addresses.multiSig.proxyAdmin, + proxyAdminOwner, + addresses.vaultEmitter.proxy + ); + + if (!deployment) { + return; + } + + await updateAddresses( + {multiSig: {endowment: {implementation: deployment.contract.address}}}, + hre + ); + + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, deployment); + } + } catch (error) { + logger.out(error, logger.Level.Error); + } + }); diff --git a/utils/deploy.ts b/utils/deploy.ts index a4b94651a..7f57f0802 100644 --- a/utils/deploy.ts +++ b/utils/deploy.ts @@ -1,7 +1,9 @@ -import {BytesLike, ContractFactory} from "ethers"; -import {ProxyContract__factory} from "typechain-types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {BytesLike, ContractFactory, Wallet} from "ethers"; +import {submitMultiSigTx} from "tasks/helpers"; +import {ITransparentUpgradeableProxy__factory, ProxyContract__factory} from "typechain-types"; import {Deployment, ProxyDeployment} from "types"; -import {getContractName, logger} from "."; +import {getContractName, isProdNetwork, logger} from "."; /** * Deploys a contract; includes logging of the relevant data @@ -23,7 +25,9 @@ export async function deploy( try { const contract = await factory.deploy(...(constructorArguments ?? [])); await contract.deployed(); - await delay(1000); + if (await isProdNetwork(contract.deployTransaction.chainId)) { + await contract.deployTransaction.wait(2); + } logger.out(`Address: ${contract.address}`); return { constructorArguments, @@ -63,6 +67,49 @@ export async function deployBehindProxy( return {implementation, proxy}; } -function delay(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); +/** + * Upgrades a proxy with a new implementation contract a contract behind a proxy; includes logging of the relevant data. + * + * Note: Deployment tx hash is logged only if the deployment fails. + * Otherwise the tx hash can be obtained by using the contract address to search the relevant Tx explorer. + * + * @param factory contract factory used to deploy the contract + * @param proxyAdmin proxy admin address + * @param initData data used to initialize the contract + * @returns object containing both implementation and proxy deployment data (including the contract instances) + */ +export async function upgradeProxy( + factory: T, + proxyAdminMultiSig: string, + proxyAdminOwner: SignerWithAddress | Wallet, + proxyToUpgrade: string +): Promise | undefined> { + const deployment = await deploy(factory); + + logger.out(`Upgrading proxy at: ${proxyToUpgrade}...`); + const payload = ITransparentUpgradeableProxy__factory.createInterface().encodeFunctionData( + "upgradeTo", + [deployment.contract.address] + ); + + const isExecuted = await submitMultiSigTx( + proxyAdminMultiSig, + proxyAdminOwner, + proxyToUpgrade, + payload + ); + if (!isExecuted) { + // The deployment will be considered valid only once the upgrade is confirmed by other ProxyAdminMultiSig owners + return; + } + + const proxy = ProxyContract__factory.connect(proxyToUpgrade, proxyAdminOwner); + const newImplAddr = await proxy.getImplementation(); + if (newImplAddr !== deployment.contract.address) { + throw new Error( + `Unexpected: expected value "${deployment.contract.address}", but got "${newImplAddr}"` + ); + } + + return deployment; } diff --git a/utils/networkHelpers.ts b/utils/networkHelpers.ts index b0c64d513..35a90e646 100644 --- a/utils/networkHelpers.ts +++ b/utils/networkHelpers.ts @@ -3,7 +3,7 @@ import {TwoWayMap} from "./twoWayMap"; import {ChainID} from "types"; import {logger} from "utils"; -export const PROD_NETWORKS = [ChainID.ethereum, ChainID.polygon]; +const PROD_NETWORKS = [ChainID.ethereum, ChainID.polygon]; // There are errors/mismatches in the axelar sdk jsons, so we just implement a lightweight // version here and use this instead. @@ -44,7 +44,10 @@ export async function getChainId(hre: HardhatRuntimeEnvironment): Promise { - const thisChainId = await getChainId(hre); +export async function isProdNetwork( + hreOrChainId: HardhatRuntimeEnvironment | number +): Promise { + const thisChainId = + typeof hreOrChainId === "number" ? hreOrChainId : await getChainId(hreOrChainId); return PROD_NETWORKS.includes(thisChainId); }