diff --git a/.env.template b/.env.template index 63a09c2fb..6743a6934 100644 --- a/.env.template +++ b/.env.template @@ -1,8 +1,3 @@ -## Network where to deploy contracts -# options=[hardhat, polygon, mumbai, goerli] -NETWORK="hardhat" -VERIFY_CONTRACTS=false - ## Etherscan explorer API config ETHERSCAN_API_KEY="put your key here plz" MAINNET_URL="https://api.etherscan.io/" diff --git a/config/index.ts b/config/index.ts index 2a18cbfa1..576ce98f0 100644 --- a/config/index.ts +++ b/config/index.ts @@ -1,14 +1,19 @@ import dotenv from "dotenv"; import {ethers} from "ethers"; import {Config} from "./types"; - +import {BigNumber} from "ethers"; dotenv.config({path: __dirname + "/./../.env"}); const config: Config = { AP_TEAM_MULTISIG_DATA: { threshold: 1, requireExecution: false, - transactionExpiry: 100000, + transactionExpiry: 604800, + }, + PROXY_ADMIN_MULTISIG_DATA: { + threshold: 1, + requireExecution: false, + transactionExpiry: 345600, }, REGISTRAR_DATA: { taxRate: 1, @@ -26,10 +31,10 @@ const config: Config = { CHARITY_APPLICATIONS_DATA: { threshold: 1, requireExecution: false, - transactionExpiry: 100000, + transactionExpiry: 345600, seedSplitToLiquid: 0, - gasAmount: 0, - seedAmount: 100, + gasAmount: BigNumber.from("180000000000000000"), // 0.18 Ether + seedAmount: 0, }, DONATION_MATCH_CHARITY_DATA: { poolFee: 300, @@ -50,6 +55,25 @@ const config: Config = { // vestingOwner : "0x1F98431c8aD98523631AE4a59f267346ea31F984", // vestingGenesisTime : 50000 }, + PROD_CONFIG: { + APTeamMultiSigOwners: [ + "0xF71eba1cf57997B6C52eA33D7939A330D6D85502", + "0x165d1f1361490974ea2F2A4079b5828E81F13b11", + "0x109641d919da899c7bd1ce27413d0c02b3bb611d", + "0x13C9060a611e4277a93ca259068256271fC2d7B4", + ], + CharityApplicationsOwners: [ + "0xF71eba1cf57997B6C52eA33D7939A330D6D85502", + "0x165d1f1361490974ea2F2A4079b5828E81F13b11", + "0x13C9060a611e4277a93ca259068256271fC2d7B4", + ], + ProxyAdminMultiSigOwners: [ + "0xF71eba1cf57997B6C52eA33D7939A330D6D85502", + "0x109641d919da899c7bd1ce27413d0c02b3bb611d", + "0x0f6d331f26C0B64fc6EACddABd5645b55cf2d8e0", + ], + Treasury: "0x4C6cDdFC00064D73E64B34aE453884de1Bf6D639", + }, }; export default config; diff --git a/config/types.ts b/config/types.ts index f1d136030..f51770e7c 100644 --- a/config/types.ts +++ b/config/types.ts @@ -7,6 +7,11 @@ export type Config = { requireExecution: boolean; transactionExpiry: number; }; + PROXY_ADMIN_MULTISIG_DATA: { + threshold: number; + requireExecution: boolean; + transactionExpiry: number; + }; REGISTRAR_DATA: { taxRate: number; acceptedTokens: { @@ -25,7 +30,7 @@ export type Config = { requireExecution: boolean; transactionExpiry: number; seedSplitToLiquid: number; - gasAmount: number; + gasAmount: BigNumber; seedAmount: number; }; DONATION_MATCH_CHARITY_DATA: { @@ -44,4 +49,10 @@ export type Config = { CommunitySpendLimit: number; distributorSpendLimit: number; }; + PROD_CONFIG: { + APTeamMultiSigOwners: string[]; + CharityApplicationsOwners: string[]; + ProxyAdminMultiSigOwners: string[]; + Treasury: string; + }; }; diff --git a/contract-address.json b/contract-address.json index 545bd3ef7..2acf09eae 100644 --- a/contract-address.json +++ b/contract-address.json @@ -131,36 +131,36 @@ }, "31337": { "accounts": { - "diamond": "0x3Ca355541eAe06EFBb53A489b89B1F2966FC044a", + "diamond": "0xb463AFC0b3A499a2D826155fc6E6E73061BEF826", "facets": { - "accountsDepositWithdrawEndowments": "0xf9Bf69b6319fe9061c549BcFf984c6fa967c3116", - "accountsAllowance": "0xFa2B78ACc38204E6aB7465d79c4FB6672Ad6EcD2", - "accountsCreateEndowment": "0x581Ca6F583472fdf76F8070dD6b23D2D2599ed86", - "accountsGasManager": "0x13AeE574292F9934ED631216E53bc8a08683cA90", - "accountsQueryEndowments": "0x78F2fb36ad2268aFdE137F152716dE7c762a5cef", - "accountsStrategy": "0x8F15FE529f12a239364219e87cC4f308d7a02932", - "accountsSwapRouter": "0x6Eb46Cb6f3EDB24A8bc942f7e357BE7befB8B0d7", - "accountsUpdate": "0xAc7337B92f469F438E26bd9AB3078CD35014462c", - "accountsUpdateEndowments": "0x5A1D883B9ecf8A4D88290d26682F625FEc620706", - "accountsUpdateEndowmentSettingsController": "0xA4C4bC12A1Ab33EeFd40BB216CcF44235d8Dc5de", - "accountsUpdateStatusEndowments": "0x06499E212Ce9F9D4a2147e82242F137c5e32f8C8", - "diamondCutFacet": "0x9f9985900ddadc4A3Cb9b626Ae78c45A9Ca4D22C", - "diamondInitFacet": "0xd5Ce55AF9EC550C4fd77B9cd8F9fa84730b53b4c", - "diamondLoupeFacet": "0x36884aEE2eB53f350a67AC5b487b5cf08ed884ac", - "ownershipFacet": "0x22b28c6461746Fa4FAa41C45Db5862be36341961" + "accountsDepositWithdrawEndowments": "0x635D1fE12b3b8af7174eED21536319b5280B4453", + "accountsAllowance": "0xBfA2d241f8f2ecaeA58A7D60E2a358f851D5c1b1", + "accountsCreateEndowment": "0x6843cd0Ccc776EA0FE7E26e6527C925F06dDD76C", + "accountsGasManager": "0x5C680949386aCD7c85FBC6f56413936f091e3f47", + "accountsQueryEndowments": "0x38f05a857a1D4FE6eB712A794a63C61D2b282b30", + "accountsStrategy": "0x84efD60753f006DE6878C7139675b110Da654459", + "accountsSwapRouter": "0x4F4d5EABF5A8fDaeE5794DEFff4eE88e6e2c5f51", + "accountsUpdate": "0x620119C4952f0648Ee905cdE00C3077CA3f9961e", + "accountsUpdateEndowments": "0x33936aF12923725cEc788e2AC5beBa03c7a5BD79", + "accountsUpdateEndowmentSettingsController": "0x243f0Fd94F12dEB0a8B73deEA25138479ee7E4aA", + "accountsUpdateStatusEndowments": "0x2A8f0893A534983c63e4F52E39dDf3527b130768", + "diamondCutFacet": "0xAb3aa8BCEA9832CB18153Aa9731E989A289277f7", + "diamondInitFacet": "0xacE2a31e8B8d66C24DAea008d1eDaf571369A728", + "diamondLoupeFacet": "0x53557e97deED0DdEEf2404a6A29A415e379051bb", + "ownershipFacet": "0xB1A33A8f6cD8572976004C3653AbCEb3E697b9ad" } }, "axelar": { - "gasService": "0xC9783d89a8e0Fd3202D84a7F8e1768Ae8383C0C0", - "gateway": "0x9D04A92f355E89afaE8609620321866dfB3a1737" + "gasService": "0x7E891709346B193ff9f37Eb739C8a294B2395Ba6", + "gateway": "0xfC8caFA21dc76a1065494E213dE9F94E788DaAC9" }, "fundraising": { "implementation": "", "proxy": "" }, "gasFwd": { - "factory": "0x600eCa807e7952AC66E81Ea44279a74Eb9c5Ba05", - "implementation": "0x1C07F4d1e01AF47146EccB64B4C526A312Ad70Df" + "factory": "0x3Bfc59C12e4f838419C483B4CCb86D5798f29DFF", + "implementation": "0x790094B9fdC8C8a83507f7Eb275DEe903Ffd71eD" }, "giftcards": { "implementation": "", @@ -218,50 +218,51 @@ } }, "indexFund": { - "implementation": "0x41E4c81a60346b5f76aD669Af7e5bCAee30107E4", - "proxy": "0x3F1E0C7b13fb5b616EADFA8fbcC439B207aD960c" + "implementation": "0x7Eb691CaD47e698642Ac507aC0383d8Ef1A20C7D", + "proxy": "0x03d1823DCE06d5bD225cB18773bb090b2aD33b5D" }, "multiSig": { "charityApplications": { - "implementation": "0x1aCC68E90145A8Db8D223370e2B29A5Aa2415169", - "proxy": "0xC2790723ab94Ad77F7B102E6010a0aEA85bFbd3E" + "implementation": "0xd9Ee17555a04f2E34ea43528628582AC45A6E984", + "proxy": "0x402e14f3f9118A3745d8554EC4106450fB91aE23" }, "apTeam": { - "implementation": "0xd8A98Ee63B135CA4d19458cBe07Ff47Ac2a9C9dF", - "proxy": "0x9a5D723096c87843E2384FC6Dc7893922277a3cE" + "implementation": "0x730EEB14F27B5D6132b9BF7D62eF877D89600F55", + "proxy": "0x45CCb6251F3500c7EE3219eE47C213fB239346cB" }, "endowment": { "emitter": { - "implementation": "0x7a576Cc05680F04D1Da3C4c33eA11e1Eba355028", - "proxy": "0xed7c73439a5A6487518B13A568951ae8C0b4F2d9" + "implementation": "0xC79662B65F21A222EE95d22557664C3BE14Ec0FE", + "proxy": "0xd62A19ffb64C3f00271Dd7BBf455824aa799d074" }, - "factory": "0x76e48b41810e5ec24f3FEa3c47a7C9Ae1d4F0F19", - "implementation": "0xd607fc8FCfc5FDF5b499daBf3C76f7349bfc624B" - } + "factory": "0x79AF01164e25B9c6Ff828A5f795CFA62A635CFC3", + "implementation": "0x7a0f853900040d5b131342018EAb9453723d9dcc" + }, + "proxyAdmin": "0x5602bAF3002df39FbAA568C0657bBBBB8e84527a" }, "registrar": { - "implementation": "0xaBCe32FBA4C591E8Ea5A5f711F7112dC08BCee74", - "proxy": "0x1BE9451496bfB6aDcFfbc308b673018a8972AFFE" + "implementation": "0xbF6b148a440acAb936796ad40947C0C33C78639A", + "proxy": "0x03Bb663AccB9FD14aD3c37B2D66B025bbd4Fc533" }, "router": { - "implementation": "0x1F624f6259d6C61224E9Fd5cD11481C271a2bf75", - "proxy": "0x5f437141bCF08A919863603C946D5c8AEa66B32b" + "implementation": "0x658E94B5FfBDe68b99203BBbBAef618D36862766", + "proxy": "0x486b1C056AC365dD969056C717ab8E7AEd59a178" }, "tokens": { "dai": "", "halo": "", "reserveToken": "", - "seedAsset": "0xF82ABBea7Edb7A6602a02eE69e6c5330C049CDa5", - "usdc": "0x715e97514F641A256bC77a6A08edd8bEA908066e", - "wmatic": "0xcC46d552a29E99c71779d05AFF3675DD90d127D6" + "seedAsset": "0xB2BD05A652973f567aD6472b9FEa29FE293f6cD9", + "usdc": "0x9B1a72BD9efC089935766f7Ebc8779B67C0F7495", + "wmatic": "0x42f293b5D45C0a949639EE229E4c9acD51DF904D" }, "uniswap": { - "factory": "0x3304eD6a8D90Ab57bb7b797aF9f66447CDf09C3E", - "swapRouter": "0x3304eD6a8D90Ab57bb7b797aF9f66447CDf09C3E" + "factory": "0x40B5D836dBeAf26c652210D8f07169B99E77C994", + "swapRouter": "0x40B5D836dBeAf26c652210D8f07169B99E77C994" }, "vaultEmitter": { - "implementation": "0x0Bd2640F272D074e0d8c2111373526bA946255A9", - "proxy": "0xEC9d58EDD9752AdC448769Fff558cE19A7473Dbc" + "implementation": "0x6eB34f65AcC0dd09C3AA72C3C4bA08578a4A3F96", + "proxy": "0x675017e864CB39CEbe4A0CDBA639750f6ee0BDE2" } }, "80001": { diff --git a/contracts/accessory/gift-cards/scripts/deploy.ts b/contracts/accessory/gift-cards/scripts/deploy.ts index 1e9ec2ca7..e24bea018 100644 --- a/contracts/accessory/gift-cards/scripts/deploy.ts +++ b/contracts/accessory/gift-cards/scripts/deploy.ts @@ -1,28 +1,29 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; import {getContractName, getSigners, logger, updateAddresses, verify} from "utils"; - import {GiftCardsMessage} from "typechain-types/contracts/accessory/gift-cards/GiftCards"; +import {GiftCards__factory, ProxyContract__factory} from "typechain-types"; export async function deployGiftCard( GiftCardsDataInput: GiftCardsMessage.InstantiateMsgStruct, + admin: string, verify_contracts: boolean, hre: HardhatRuntimeEnvironment ) { try { - const {ethers, run, network} = hre; - const {proxyAdmin} = await getSigners(hre); - const GiftCards = await ethers.getContractFactory("GiftCards"); + const {deployer} = await getSigners(hre); + + const GiftCards = new GiftCards__factory(deployer); const GiftCardsInstance = await GiftCards.deploy(); await GiftCardsInstance.deployed(); logger.out(`GiftCards implementation address: ${GiftCardsInstance.address}"`); - const ProxyContract = await ethers.getContractFactory("ProxyContract"); + const ProxyContract = new ProxyContract__factory(deployer); const GiftCardsData = GiftCardsInstance.interface.encodeFunctionData("initialize", [ GiftCardsDataInput, ]); const GiftCardsProxy = await ProxyContract.deploy( GiftCardsInstance.address, - proxyAdmin.address, + admin, GiftCardsData ); await GiftCardsProxy.deployed(); @@ -42,7 +43,7 @@ export async function deployGiftCard( if (verify_contracts) { await verify(hre, { address: GiftCardsProxy.address, - constructorArguments: [GiftCardsInstance.address, proxyAdmin.address, GiftCardsData], + constructorArguments: [GiftCardsInstance.address, admin, GiftCardsData], contractName: getContractName(GiftCards), }); } diff --git a/contracts/core/accounts/diamond/Diamond.sol b/contracts/core/accounts/diamond/Diamond.sol index b1af99f17..0869cdf46 100644 --- a/contracts/core/accounts/diamond/Diamond.sol +++ b/contracts/core/accounts/diamond/Diamond.sol @@ -3,11 +3,12 @@ pragma solidity ^0.8.19; import {LibDiamond} from "./libraries/LibDiamond.sol"; import {IDiamondCut} from "./interfaces/IDiamondCut.sol"; +import {Validator} from "../../validator.sol"; contract Diamond { constructor(address contractowner, address diamondcutfacet) payable { - require(contractowner != address(0), "Invalid Address"); - require(diamondcutfacet != address(0), "Invalid Address"); + require(Validator.addressChecker(contractowner), "Invalid Address"); + require(Validator.addressChecker(diamondcutfacet), "Invalid Address"); LibDiamond.setContractOwner(contractowner); // Add the diamondCut external function from the diamondCutFacet @@ -33,7 +34,7 @@ contract Diamond { } // get facet from function selector address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress; - require(facet != address(0), "Diamond: Function does not exist"); + require(Validator.addressChecker(facet), "Diamond: Function does not exist"); // Execute external function from facet using delegatecall and return any value. assembly { // copy function selector and any arguments diff --git a/contracts/core/accounts/diamond/facets/OwnershipFacet.sol b/contracts/core/accounts/diamond/facets/OwnershipFacet.sol index 21744e8ae..8d5f31ffa 100644 --- a/contracts/core/accounts/diamond/facets/OwnershipFacet.sol +++ b/contracts/core/accounts/diamond/facets/OwnershipFacet.sol @@ -8,11 +8,11 @@ import {Validator} from "../../../validator.sol"; contract OwnershipFacet is IERC173 { function transferOwnership(address newOwner) external override { LibDiamond.enforceIsContractOwner(); + require(Validator.addressChecker(newOwner), "Invalid address"); LibDiamond.setContractOwner(newOwner); } function owner() external view override returns (address owner_) { - require(Validator.addressChecker(owner_), "Invalid address"); owner_ = LibDiamond.contractOwner(); } } diff --git a/contracts/core/accounts/scripts/deploy/deploy.ts b/contracts/core/accounts/scripts/deploy/deploy.ts index 864e1d1a2..c097818b6 100644 --- a/contracts/core/accounts/scripts/deploy/deploy.ts +++ b/contracts/core/accounts/scripts/deploy/deploy.ts @@ -1,13 +1,20 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {HardhatRuntimeEnvironment} from "hardhat/types"; -import {DiamondCutFacet__factory, DiamondInit__factory, Diamond__factory} from "typechain-types"; -import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; +import { + DiamondCutFacet__factory, + DiamondInit__factory, + Diamond__factory, + IERC173__factory, +} from "typechain-types"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; import cutDiamond from "./cutDiamond"; import deployFacets from "./deployFacets"; export async function deployAccountsDiamond( owner: string, registrar: string, + diamondAdmin: string, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{ diamond: Deployment; @@ -15,15 +22,15 @@ export async function deployAccountsDiamond( }> { logger.out("Deploying and setting up Accounts Diamond and all its facets..."); - const {proxyAdmin} = await getSigners(hre); + const {diamond, diamondCutFacet} = await deployDiamond(deployer, hre); - const {diamond, diamondCutFacet} = await deployDiamond(proxyAdmin, hre); + const diamondInit = await deployDiamondInit(deployer, hre); - const diamondInit = await deployDiamondInit(proxyAdmin, hre); + const cuts = await deployFacets(deployer, hre); - const cuts = await deployFacets(proxyAdmin, hre); + await cutDiamond(diamond.address, diamondInit.address, deployer, owner, registrar, cuts, hre); - await cutDiamond(diamond.address, diamondInit.address, proxyAdmin, owner, registrar, cuts, hre); + await setDiamondContractOwner(diamond.address, diamondAdmin, deployer); return { diamond, @@ -37,19 +44,19 @@ export async function deployAccountsDiamond( } async function deployDiamond( - admin: SignerWithAddress, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{diamond: Deployment; diamondCutFacet: Deployment}> { - const DiamondCutFacet = new DiamondCutFacet__factory(admin); + const DiamondCutFacet = new DiamondCutFacet__factory(deployer); const diamondCutFacet = await DiamondCutFacet.deploy(); await diamondCutFacet.deployed(); logger.out(`DiamondCutFacet deployed at: ${diamondCutFacet.address}`); const constructorArguments: Parameters = [ - admin.address, + deployer.address, diamondCutFacet.address, ]; - const Diamond = new Diamond__factory(admin); + const Diamond = new Diamond__factory(deployer); const diamond = await Diamond.deploy(...constructorArguments); await diamond.deployed(); logger.out(`Diamond deployed at: ${diamond.address}`); @@ -93,3 +100,15 @@ async function deployDiamondInit( contractName: getContractName(DiamondInit), }; } + +async function setDiamondContractOwner( + address: string, + newOwner: string, + curOwner: SignerWithAddress +) { + logger.out(`Transferring ownership from "${curOwner}" to "${newOwner}"...`); + const accountsDiamond = IERC173__factory.connect(address, curOwner); + const tx = await accountsDiamond.transferOwnership(newOwner); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); +} diff --git a/contracts/core/gasFwd/GasFwd.sol b/contracts/core/gasFwd/GasFwd.sol index d7379c893..e4aea1e80 100644 --- a/contracts/core/gasFwd/GasFwd.sol +++ b/contracts/core/gasFwd/GasFwd.sol @@ -5,6 +5,7 @@ import {IGasFwd} from "./IGasFwd.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Validator} from "../validator.sol"; contract GasFwd is IGasFwd, Initializable { error OnlyAccounts(); @@ -16,6 +17,7 @@ contract GasFwd is IGasFwd, Initializable { address accounts; function initialize(address _accounts) public initializer { + require(Validator.addressChecker(_accounts), "Invalid Accounts address"); accounts = _accounts; } diff --git a/contracts/core/gasFwd/scripts/deploy.ts b/contracts/core/gasFwd/scripts/deploy.ts index c7d0f402f..2c62d674a 100644 --- a/contracts/core/gasFwd/scripts/deploy.ts +++ b/contracts/core/gasFwd/scripts/deploy.ts @@ -4,18 +4,20 @@ import {GasFwdFactory__factory, GasFwd__factory} from "typechain-types"; import {Deployment, getAddresses, getContractName, logger, updateAddresses} from "utils"; type Data = { - admin: SignerWithAddress; + deployer: SignerWithAddress; + proxyAdmin: string; + factoryOwner: string; registrar?: string; }; export async function deployGasFwd( - {admin, registrar}: Data, + {deployer, proxyAdmin, factoryOwner, registrar}: Data, hre: HardhatRuntimeEnvironment ): Promise<{factory: Deployment; implementation: Deployment}> { logger.out("Deploying Gas Forwarder..."); logger.out("Deploying GasFwd implementation..."); - const GF = new GasFwd__factory(admin); + const GF = new GasFwd__factory(deployer); const gf = await GF.deploy(); await gf.deployed(); logger.out(`Address: ${gf.address}`); @@ -24,16 +26,21 @@ export async function deployGasFwd( let registrarAddress = registrar ? registrar : addresses.registrar.proxy; logger.out("Deploying factory..."); - const GFF = new GasFwdFactory__factory(admin); + const GFF = new GasFwdFactory__factory(deployer); const constructorArguments: Parameters = [ gf.address, - admin.address, + proxyAdmin, registrarAddress, ]; const gff = await GFF.deploy(...constructorArguments); await gff.deployed(); logger.out(`Address: ${gff.address}`); + logger.out(`Transferring ownership to: ${factoryOwner}...`); + const tx = await gff.transferOwnership(factoryOwner); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + await updateAddresses( { gasFwd: { diff --git a/contracts/core/index-fund/scripts/deploy.ts b/contracts/core/index-fund/scripts/deploy.ts index 8e35962cd..3c676c86b 100644 --- a/contracts/core/index-fund/scripts/deploy.ts +++ b/contracts/core/index-fund/scripts/deploy.ts @@ -1,11 +1,14 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import config from "config"; import {HardhatRuntimeEnvironment} from "hardhat/types"; import {IndexFund__factory, ProxyContract__factory} from "typechain-types"; -import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; export async function deployIndexFund( registrar: string, owner: string, + proxyAdmin: string, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{ implementation: Deployment; @@ -13,11 +16,9 @@ export async function deployIndexFund( }> { logger.out("Deploying IndexFund..."); - const {deployer, proxyAdmin} = await getSigners(hre); - // deploy implementation logger.out("Deploying implementation..."); - const indexFundFactory = new IndexFund__factory(proxyAdmin); + const indexFundFactory = new IndexFund__factory(deployer); const indexFund = await indexFundFactory.deploy(); await indexFund.deployed(); logger.out(`Address: ${indexFund.address}`); @@ -30,14 +31,15 @@ export async function deployIndexFund( config.INDEX_FUND_DATA.fundingGoal, ]); const proxyFactory = new ProxyContract__factory(deployer); - const indexFundProxy = await proxyFactory.deploy(indexFund.address, proxyAdmin.address, initData); + const indexFundProxy = await proxyFactory.deploy(indexFund.address, proxyAdmin, initData); await indexFundProxy.deployed(); logger.out(`Address: ${indexFundProxy.address}`); // update owner - logger.out(`Updating IndexFund owner to: ${owner}...`); + logger.out(`Transferring ownership to: ${owner}...`); const proxiedIndexFund = IndexFund__factory.connect(indexFundProxy.address, deployer); const tx = await proxiedIndexFund.transferOwnership(owner); + logger.out(`Tx hash: ${tx.hash}`); await tx.wait(); // update address file & verify contracts diff --git a/contracts/core/registrar/scripts/deploy.ts b/contracts/core/registrar/scripts/deploy.ts index 9edf0149f..499602458 100644 --- a/contracts/core/registrar/scripts/deploy.ts +++ b/contracts/core/registrar/scripts/deploy.ts @@ -9,7 +9,7 @@ type RegistrarDeployData = { router: string; owner: string; deployer: SignerWithAddress; - proxyAdmin: SignerWithAddress; + proxyAdmin: string; treasury: string; apTeamMultisig: string; }; @@ -36,7 +36,7 @@ export async function deployRegistrar( // deploy implementation logger.out("Deploying implementation..."); - const factory = new Registrar__factory(proxyAdmin); + const factory = new Registrar__factory(deployer); const registrar = await factory.deploy(); await registrar.deployed(); logger.out(`Address: ${registrar.address}`); @@ -58,7 +58,7 @@ export async function deployRegistrar( ] ); const proxyFactory = new ProxyContract__factory(deployer); - const proxy = await proxyFactory.deploy(registrar.address, proxyAdmin.address, initData); + const proxy = await proxyFactory.deploy(registrar.address, proxyAdmin, initData); await proxy.deployed(); logger.out(`Address: ${proxy.address}`); @@ -88,7 +88,7 @@ export async function deployRegistrar( type LocalRegistrarDeployData = { owner: string; deployer: SignerWithAddress; - proxyAdmin: SignerWithAddress; + proxyAdmin: string; }; export async function deployLocalRegistrar( @@ -102,7 +102,7 @@ export async function deployLocalRegistrar( // deploy implementation logger.out("Deploying implementation..."); - const factory = new LocalRegistrar__factory(proxyAdmin); + const factory = new LocalRegistrar__factory(deployer); const localRegistrar = await factory.deploy(); await localRegistrar.deployed(); logger.out(`Address: ${localRegistrar.address}`); @@ -113,7 +113,7 @@ export async function deployLocalRegistrar( const initData = localRegistrar.interface.encodeFunctionData("initialize", [ await getAxlNetworkName(hre), ]); - const proxy = await proxyFactory.deploy(localRegistrar.address, proxyAdmin.address, initData); + const proxy = await proxyFactory.deploy(localRegistrar.address, proxyAdmin, initData); await proxy.deployed(); logger.out(`Address: ${proxy.address}`); diff --git a/contracts/core/router/scripts/deploy.ts b/contracts/core/router/scripts/deploy.ts index 956b07d18..e9aa96b4f 100644 --- a/contracts/core/router/scripts/deploy.ts +++ b/contracts/core/router/scripts/deploy.ts @@ -1,21 +1,23 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {ProxyContract__factory, Router__factory} from "typechain-types"; -import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; export async function deployRouter( registrar: string, + proxyAdmin: string, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{ implementation: Deployment; proxy: Deployment; }> { + logger.divider(); logger.out("Deploying Router..."); - const {proxyAdmin} = await getSigners(hre); - // deploy implementation logger.out("Deploying implementation..."); - const routerFactory = new Router__factory(proxyAdmin); + const routerFactory = new Router__factory(deployer); const router = await routerFactory.deploy(); await router.deployed(); logger.out(`Address: ${router.address}.`); @@ -23,8 +25,8 @@ export async function deployRouter( // deploy proxy logger.out("Deploying proxy..."); const initData = router.interface.encodeFunctionData("initialize", [registrar]); - const routerProxyFactory = new ProxyContract__factory(proxyAdmin); - const routerProxy = await routerProxyFactory.deploy(router.address, proxyAdmin.address, initData); + const routerProxyFactory = new ProxyContract__factory(deployer); + const routerProxy = await routerProxyFactory.deploy(router.address, proxyAdmin, initData); await routerProxy.deployed(); logger.out(`Address: ${routerProxy.address}.`); diff --git a/contracts/core/vault/scripts/deployVaultEmitter.ts b/contracts/core/vault/scripts/deployVaultEmitter.ts index d7e1f85e9..52d61fb02 100644 --- a/contracts/core/vault/scripts/deployVaultEmitter.ts +++ b/contracts/core/vault/scripts/deployVaultEmitter.ts @@ -1,17 +1,20 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {ProxyContract__factory, VaultEmitter__factory} from "typechain-types"; -import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; -export async function deployVaultEmitter(hre: HardhatRuntimeEnvironment): Promise<{ +export async function deployVaultEmitter( + proxyAdmin: string, + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise<{ implementation: Deployment; proxy: Deployment; }> { logger.out("Deploying VaultEmitter..."); - const {proxyAdmin} = await getSigners(hre); - logger.out("Deploying implementation..."); - const Emitter = new VaultEmitter__factory(proxyAdmin); + const Emitter = new VaultEmitter__factory(deployer); const emitter = await Emitter.deploy(); logger.out(`Tx hash: ${emitter.deployTransaction.hash}`); await emitter.deployed(); @@ -19,8 +22,8 @@ export async function deployVaultEmitter(hre: HardhatRuntimeEnvironment): Promis logger.out("Deploying proxy..."); const initData = emitter.interface.encodeFunctionData("initialize"); - const Proxy = new ProxyContract__factory(proxyAdmin); - const proxy = await Proxy.deploy(emitter.address, proxyAdmin.address, initData); + const Proxy = new ProxyContract__factory(deployer); + const proxy = await Proxy.deploy(emitter.address, proxyAdmin, initData); logger.out(`Tx hash: ${proxy.deployTransaction.hash}`); await proxy.deployed(); logger.out(`Address: ${proxy.address}`); diff --git a/contracts/integrations/goldfinch/GFITrader.sol b/contracts/integrations/goldfinch/GFITrader.sol index e2e45ca80..7cf727186 100644 --- a/contracts/integrations/goldfinch/GFITrader.sol +++ b/contracts/integrations/goldfinch/GFITrader.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.0; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import {Validator} from "../../core/validator.sol"; contract GFITrader { ISwapRouter swapRouter; @@ -15,6 +16,10 @@ contract GFITrader { uint24 public constant poolFee = 3000; constructor(address _swapRouterAddr, address _gfi, address _weth9, address _usdc) { + require(Validator.addressChecker(_swapRouterAddr), "Invalid swap router address"); + require(Validator.addressChecker(_gfi), "Invalid GFI Address"); + require(Validator.addressChecker(_weth9), "Invalid wETH Address"); + require(Validator.addressChecker(_usdc), "Invalid USDC Address"); swapRouter = ISwapRouter(_swapRouterAddr); GFI = _gfi; WETH9 = _weth9; diff --git a/contracts/multisigs/CharityApplications.sol b/contracts/multisigs/CharityApplications.sol index 20de85eeb..6feeff8ec 100644 --- a/contracts/multisigs/CharityApplications.sol +++ b/contracts/multisigs/CharityApplications.sol @@ -57,10 +57,7 @@ contract CharityApplications is MultiSigGeneric, StorageApplications, ICharityAp } modifier proposalApprovalsThresholdMet(uint256 proposalId) { - require( - proposalConfirmations[proposalId].count >= approvalsRequired, - "Not enough confirmations to execute" - ); + require(isProposalConfirmed(proposalId), "Not enough confirmations to execute"); _; } @@ -181,7 +178,7 @@ contract CharityApplications is MultiSigGeneric, StorageApplications, ICharityAp proposalConfirmations[proposalId].count += 1; emit ApplicationConfirmed(proposalId, msg.sender); // if execution is required, do not auto-execute - if (!requireExecution) { + if (!requireExecution && isProposalConfirmed(proposalId)) { executeProposal(proposalId); } } @@ -327,4 +324,11 @@ contract CharityApplications is MultiSigGeneric, StorageApplications, ICharityAp ) public view override proposalExists(proposalId) returns (uint256) { return proposalConfirmations[proposalId].count; } + + /// @dev Returns the confirmation status of a transaction. + /// @param proposalId Proposal ID. + /// @return bool Confirmation status. + function isProposalConfirmed(uint256 proposalId) public view returns (bool) { + return proposalConfirmations[proposalId].count >= approvalsRequired; + } } diff --git a/contracts/multisigs/MultiSigGeneric.sol b/contracts/multisigs/MultiSigGeneric.sol index e4517d278..0eed2f190 100644 --- a/contracts/multisigs/MultiSigGeneric.sol +++ b/contracts/multisigs/MultiSigGeneric.sol @@ -26,12 +26,12 @@ contract MultiSigGeneric is } modifier ownerDoesNotExist(address _owner) { - require(!isOwner[_owner], "Owner address dne"); + require(!isOwner[_owner], "Already is an owner"); _; } modifier ownerExists(address _owner) { - require(isOwner[_owner], "Owner address already exists"); + require(isOwner[_owner], "Owner address dne"); _; } @@ -67,10 +67,7 @@ contract MultiSigGeneric is } modifier approvalsThresholdMet(uint256 transactionId) { - require( - confirmations[transactionId].count >= approvalsRequired, - "Not enough confirmations to execute" - ); + require(isConfirmed(transactionId), "Not enough confirmations to execute"); _; } @@ -205,7 +202,7 @@ contract MultiSigGeneric is confirmations[transactionId].count += 1; emitTransactionConfirmed(msg.sender, transactionId); // if execution is not required and confirmation count is met, execute - if (!requireExecution && confirmations[transactionId].count >= approvalsRequired) { + if (!requireExecution && isConfirmed(transactionId)) { executeTransaction(transactionId); } } @@ -271,10 +268,9 @@ contract MultiSigGeneric is /// @dev Returns the confirmation status of a transaction. /// @param transactionId Transaction ID. - /// @return Confirmation status. + /// @return bool Confirmation status. function isConfirmed(uint256 transactionId) public view override returns (bool) { - if (confirmations[transactionId].count >= approvalsRequired) return true; - return false; + return confirmations[transactionId].count >= approvalsRequired; } /// @dev Returns number of confirmations of a transaction. diff --git a/contracts/multisigs/ProxyAdminMultiSig.sol b/contracts/multisigs/ProxyAdminMultiSig.sol new file mode 100644 index 000000000..b77cbdc67 --- /dev/null +++ b/contracts/multisigs/ProxyAdminMultiSig.sol @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {Validator} from "../core/validator.sol"; +import {StorageMultiSig, MultiSigStorage} from "./storage.sol"; +import {IMultiSigGeneric} from "./interfaces/IMultiSigGeneric.sol"; +import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {Utils} from "../lib/utils.sol"; + +contract ProxyAdminMultiSig is StorageMultiSig, IMultiSigGeneric, ERC165, ReentrancyGuard { + /// @dev Contract constructor sets initial owners and required number of confirmations. + /// @param owners List of initial owners. + /// @param _approvalsRequired Number of required confirmations. + /// @param _requireExecution setting for if an explicit execution call is required + /// @param _transactionExpiry Proposal expiry time in seconds + constructor( + address[] memory owners, + uint256 _approvalsRequired, + bool _requireExecution, + uint256 _transactionExpiry + ) validApprovalsRequirement(owners.length, _approvalsRequired) { + require(owners.length > 0, "Must pass at least one owner address"); + for (uint256 i = 0; i < owners.length; i++) { + require( + Validator.addressChecker(owners[i]), + string.concat("Invalid owner address at index: ", Strings.toString(i)) + ); + isOwner[owners[i]] = true; + } + activeOwnersCount = owners.length; + + // set storage variables + approvalsRequired = _approvalsRequired; + requireExecution = _requireExecution; + transactionExpiry = _transactionExpiry; + emitInitializedMultiSig(owners, approvalsRequired, requireExecution, transactionExpiry); + } + + /* + * Modifiers + */ + modifier onlyWallet() { + require(msg.sender == address(this), "Can only be called by the MultiSig itself"); + _; + } + + modifier ownerDoesNotExist(address _owner) { + require(!isOwner[_owner], "Already is an owner"); + _; + } + + modifier ownerExists(address _owner) { + require(isOwner[_owner], "Owner address dne"); + _; + } + + modifier transactionExists(uint256 transactionId) { + require(Validator.addressChecker(transactions[transactionId].destination), "Transaction dne"); + _; + } + + modifier confirmed(uint256 transactionId, address _owner) { + require( + confirmations[transactionId].confirmationsByOwner[_owner], + "Transaction is not confirmed" + ); + _; + } + + modifier notConfirmed(uint256 transactionId, address _owner) { + require( + !confirmations[transactionId].confirmationsByOwner[_owner], + "Transaction is already confirmed" + ); + _; + } + + modifier notExecuted(uint256 transactionId) { + require(!transactions[transactionId].executed, "Transaction is executed"); + _; + } + + modifier notExpired(uint256 transactionId) { + require(transactions[transactionId].expiry > block.timestamp, "Transaction is expired"); + _; + } + + modifier approvalsThresholdMet(uint256 transactionId) { + require( + confirmations[transactionId].count >= approvalsRequired, + "Not enough confirmations to execute" + ); + _; + } + + modifier validApprovalsRequirement(uint256 _ownerCount, uint256 _approvalsRequired) { + require( + _approvalsRequired <= _ownerCount && _approvalsRequired != 0, + "Invalid approvals requirement" + ); + _; + } + + /// @dev Receive function allows to deposit ether. + receive() external payable override {} + + /// @dev Fallback function allows to deposit ether. + fallback() external payable override {} + + /* + * Public functions + */ + + /// @dev Allows to add new owners. Transaction has to be sent by wallet. + /// @param owners Addresses of new owners. + function addOwners(address[] memory owners) public virtual override onlyWallet { + require(owners.length > 0, "Empty new owners list passed"); + for (uint256 o = 0; o < owners.length; o++) { + require( + Validator.addressChecker(owners[o]), + string.concat("Invalid owner address at index: ", Strings.toString(o)) + ); + require(!isOwner[owners[o]], "New owner already exists"); + // set the owner address to false in mapping + isOwner[owners[o]] = true; + } + activeOwnersCount += owners.length; + emitOwnersAdded(owners); + } + + /// @dev Allows to remove owners. Transaction has to be sent by wallet. + /// @param owners Addresses of removed owners. + function removeOwners(address[] memory owners) public virtual override onlyWallet { + require( + owners.length < activeOwnersCount, + "Must have at least one owner left after all removals" + ); + // check that all ousted owners are current, existing owners + for (uint256 o = 0; o < owners.length; o++) { + require(isOwner[owners[o]], "Ousted owner is not a current owner"); + // set the owner address to false in mapping + isOwner[owners[o]] = false; + } + activeOwnersCount -= owners.length; + emitOwnersRemoved(owners); + // adjust the approval threshold downward if we've removed more members than can meet the currently + // set threshold level. (ex. Prevent 10 owners total needing 15 approvals to execute txs) + if (approvalsRequired > activeOwnersCount) changeApprovalsRequirement(activeOwnersCount); + } + + /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + /// @param currOwner Address of current owner to be replaced. + /// @param newOwner Address of new owner. + function replaceOwner( + address currOwner, + address newOwner + ) public virtual override onlyWallet ownerExists(currOwner) ownerDoesNotExist(newOwner) { + require(Validator.addressChecker(newOwner), "Invalid new owner address"); + isOwner[currOwner] = false; + isOwner[newOwner] = true; + emitOwnerReplaced(currOwner, newOwner); + } + + /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet. + /// @param _approvalsRequired Number of required confirmations. + function changeApprovalsRequirement( + uint256 _approvalsRequired + ) + public + virtual + override + onlyWallet + validApprovalsRequirement(activeOwnersCount, _approvalsRequired) + { + approvalsRequired = _approvalsRequired; + emitApprovalsRequiredChanged(_approvalsRequired); + } + + /// @dev Allows to change whether explicit execution step is needed once the required number of confirmations is met. Transaction has to be sent by wallet. + /// @param _requireExecution Is an explicit execution step is needed + function changeRequireExecution(bool _requireExecution) public virtual override onlyWallet { + requireExecution = _requireExecution; + emitRequireExecutionChanged(_requireExecution); + } + + /// @dev Allows to change the expiry time for transactions. + /// @param _transactionExpiry time that a newly created transaction is valid for + function changeTransactionExpiry(uint256 _transactionExpiry) public virtual override onlyWallet { + transactionExpiry = _transactionExpiry; + emitExpiryChanged(_transactionExpiry); + } + + /// @dev Allows an owner to submit and confirm a transaction. + /// @param destination Transaction target address. + /// @param value Transaction ether value. + /// @param data Transaction data payload. + /// @param metadata Encoded transaction metadata, can contain dynamic content. + /// @return transactionId transaction ID. + function submitTransaction( + address destination, + uint256 value, + bytes memory data, + bytes memory metadata + ) public virtual override returns (uint256 transactionId) { + transactionId = addTransaction(destination, value, data, metadata); + confirmTransaction(transactionId); + } + + /// @dev Allows an owner to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction( + uint256 transactionId + ) + public + virtual + override + nonReentrant + ownerExists(msg.sender) + transactionExists(transactionId) + notConfirmed(transactionId, msg.sender) + notExpired(transactionId) + { + confirmations[transactionId].confirmationsByOwner[msg.sender] = true; + confirmations[transactionId].count += 1; + emitTransactionConfirmed(msg.sender, transactionId); + // if execution is not required and confirmation count is met, execute + if (!requireExecution && confirmations[transactionId].count >= approvalsRequired) { + executeTransaction(transactionId); + } + } + + /// @dev Allows an owner to revoke a confirmation for a transaction. + /// @param transactionId Transaction ID. + function revokeConfirmation( + uint256 transactionId + ) + public + virtual + override + nonReentrant + ownerExists(msg.sender) + confirmed(transactionId, msg.sender) + notExecuted(transactionId) + notExpired(transactionId) + { + confirmations[transactionId].confirmationsByOwner[msg.sender] = false; + confirmations[transactionId].count -= 1; + emitTransactionConfirmationRevoked(msg.sender, transactionId); + } + + /// @dev Allows current owners to revoke a confirmation for a non-executed transaction from a removed/non-current owner. + /// @param transactionId Transaction ID. + /// @param formerOwner Address of the non-current owner, whos confirmation is being revoked + function revokeConfirmationOfFormerOwner( + uint256 transactionId, + address formerOwner + ) + public + virtual + override + nonReentrant + ownerExists(msg.sender) + confirmed(transactionId, formerOwner) + notExecuted(transactionId) + notExpired(transactionId) + { + require(!isOwner[formerOwner], "Attempting to revert confirmation of a current owner"); + confirmations[transactionId].confirmationsByOwner[formerOwner] = false; + confirmations[transactionId].count -= 1; + emitTransactionConfirmationRevoked(formerOwner, transactionId); + } + + /// @dev Allows anyone to execute a confirmed transaction. + /// @param transactionId Transaction ID. + function executeTransaction( + uint256 transactionId + ) + public + virtual + override + approvalsThresholdMet(transactionId) + notExecuted(transactionId) + notExpired(transactionId) + { + MultiSigStorage.Transaction storage txn = transactions[transactionId]; + txn.executed = true; + Utils._execute(txn.destination, txn.value, txn.data); + emitTransactionExecuted(transactionId); + } + + /// @dev Returns the confirmation status of a transaction. + /// @param transactionId Transaction ID. + /// @return Confirmation status. + function isConfirmed(uint256 transactionId) public view override returns (bool) { + if (confirmations[transactionId].count >= approvalsRequired) return true; + return false; + } + + /// @dev Returns number of confirmations of a transaction. + /// @param transactionId Transaction ID. + /// @return uint256 + function getConfirmationCount( + uint256 transactionId + ) public view override transactionExists(transactionId) returns (uint256) { + return confirmations[transactionId].count; + } + + function getConfirmationStatus( + uint256 transactionId, + address ownerAddr + ) public view override transactionExists(transactionId) returns (bool) { + return confirmations[transactionId].confirmationsByOwner[ownerAddr]; + } + + /// @dev Returns whether an address is an active owner. + /// @return Bool. True if owner is an active owner. + function getOwnerStatus(address ownerAddr) public view override returns (bool) { + return isOwner[ownerAddr]; + } + + /* + * Internal functions + */ + /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet. + /// @param destination Transaction target address. + /// @param value Transaction ether value. + /// @param data Transaction data payload. + /// @param metadata Encoded transaction metadata, can contain dynamic content. + /// @return transactionId Returns transaction ID. + function addTransaction( + address destination, + uint256 value, + bytes memory data, + bytes memory metadata + ) internal virtual override returns (uint256 transactionId) { + require(Validator.addressChecker(destination), "Invalid destination address"); + transactionId = transactionCount; + transactions[transactionId] = MultiSigStorage.Transaction({ + destination: destination, + value: value, + data: data, + expiry: block.timestamp + transactionExpiry, + executed: false, + metadata: metadata + }); + transactionCount += 1; + emitTransactionSubmitted(msg.sender, transactionId, metadata); + } + + /// @dev Emits an event post-initialization. + /// @param owners List of initial owners. + /// @param _approvalsRequired Number of required confirmations. + /// @param _requireExecution setting for if an explicit execution call is required. + /// @param _transactionExpiry Proposal expiry time in seconds. + function emitInitializedMultiSig( + address[] memory owners, + uint256 _approvalsRequired, + bool _requireExecution, + uint256 _transactionExpiry + ) internal virtual { + emit InitializedMultiSig( + address(this), + owners, + _approvalsRequired, + _requireExecution, + _transactionExpiry + ); + } + + /// @dev Emits an event when owners are added. + /// @param owners Addresses of new owners. + function emitOwnersAdded(address[] memory owners) internal virtual { + emit OwnersAdded(address(this), owners); + } + + /// @dev Emits an event when owners are removed. + /// @param owners Addresses of new owners. + function emitOwnersRemoved(address[] memory owners) internal virtual { + emit OwnersRemoved(address(this), owners); + } + + /// @dev Emits an event when owners are replaced. + /// @param currOwner Address of current owner to be replaced. + /// @param newOwner Address of new owner. + function emitOwnerReplaced(address currOwner, address newOwner) internal virtual { + emit OwnerReplaced(address(this), currOwner, newOwner); + } + + /// @dev Emits an event when the number of required confirmations is updated. + /// @param _approvalsRequired Number of required confirmations. + function emitApprovalsRequiredChanged(uint256 _approvalsRequired) internal virtual { + emit ApprovalsRequiredChanged(address(this), _approvalsRequired); + } + + /// @dev Emits an event when there's an update to the flag indicating whether explicit execution step is needed. + /// @param _requireExecution Is an explicit execution step is needed. + function emitRequireExecutionChanged(bool _requireExecution) internal virtual { + emit RequireExecutionChanged(address(this), _requireExecution); + } + + /// @dev Emits an event when expiry time for transactions is updated. + /// @param _transactionExpiry time that a newly created transaction is valid for. + function emitExpiryChanged(uint256 _transactionExpiry) internal virtual { + emit ExpiryChanged(address(this), _transactionExpiry); + } + + /// @dev Emits an event when a transaction is submitted. + /// @param sender Sender of the Transaction. + /// @param transactionId Transaction ID. + /// @param metadata Encoded transaction metadata, can contain dynamic content. + function emitTransactionSubmitted( + address sender, + uint256 transactionId, + bytes memory metadata + ) internal virtual { + emit TransactionSubmitted(address(this), sender, transactionId, metadata); + } + + /// @dev Emits an event when a transaction is confirmed. + /// @param sender Sender of the Transaction. + /// @param transactionId Transaction ID. + function emitTransactionConfirmed(address sender, uint256 transactionId) internal virtual { + emit TransactionConfirmed(address(this), sender, transactionId); + } + + /// @dev Emits an event when a transaction confirmation is revoked. + /// @param sender Sender of the Transaction. + /// @param transactionId Transaction ID. + function emitTransactionConfirmationRevoked( + address sender, + uint256 transactionId + ) internal virtual { + emit TransactionConfirmationRevoked(address(this), sender, transactionId); + } + + /// @dev Emits an event when a transaction is executed. + /// @param transactionId Transaction ID. + function emitTransactionExecuted(uint256 transactionId) internal virtual { + emit TransactionExecuted(address(this), transactionId); + } +} diff --git a/contracts/multisigs/endowment-multisig/EndowmentMultiSigFactory.sol b/contracts/multisigs/endowment-multisig/EndowmentMultiSigFactory.sol index 66db4105d..bf6b10755 100644 --- a/contracts/multisigs/endowment-multisig/EndowmentMultiSigFactory.sol +++ b/contracts/multisigs/endowment-multisig/EndowmentMultiSigFactory.sol @@ -24,21 +24,21 @@ contract EndowmentMultiSigFactory is Ownable { mapping(address => address[]) public instantiations; mapping(uint256 => address) public endowmentIdToMultisig; - address IMPLEMENTATION_ADDRESS; - address PROXY_ADMIN; + address public implementationAddress; + address public proxyAdmin; IRegistrar registrar; - constructor(address implementationAddress, address proxyAdmin, address _registrar) { - require(implementationAddress != address(0), "Invalid Address"); - require(proxyAdmin != address(0), "Invalid Address"); + constructor(address _implementationAddress, address _proxyAdmin, address _registrar) { + require(_implementationAddress != address(0), "Invalid Address"); + require(_proxyAdmin != address(0), "Invalid Address"); require(_registrar != address(0), "Invalid Address"); registrar = IRegistrar(_registrar); - IMPLEMENTATION_ADDRESS = implementationAddress; - emit ImplementationUpdated(implementationAddress); + implementationAddress = _implementationAddress; + emit ImplementationUpdated(_implementationAddress); - PROXY_ADMIN = proxyAdmin; - emit ProxyAdminUpdated(proxyAdmin); + proxyAdmin = _proxyAdmin; + emit ProxyAdminUpdated(_proxyAdmin); } modifier onlyAccountsContract() { @@ -59,22 +59,22 @@ contract EndowmentMultiSigFactory is Ownable { /** * @dev Updates the implementation address - * @param implementationAddress The address of the new implementation + * @param _implementationAddress The address of the new implementation */ - function updateImplementation(address implementationAddress) public onlyOwner { - require(implementationAddress != address(0), "Invalid Address"); - IMPLEMENTATION_ADDRESS = implementationAddress; - emit ImplementationUpdated(implementationAddress); + function updateImplementation(address _implementationAddress) public onlyOwner { + require(_implementationAddress != address(0), "Invalid Address"); + implementationAddress = _implementationAddress; + emit ImplementationUpdated(_implementationAddress); } /** * @dev Updates the proxy admin address - * @param proxyAdmin The address of the new proxy admin + * @param _proxyAdmin The address of the new proxy admin */ - function updateProxyAdmin(address proxyAdmin) public onlyOwner { - require(proxyAdmin != address(0), "Invalid Address"); - PROXY_ADMIN = proxyAdmin; - emit ProxyAdminUpdated(proxyAdmin); + function updateProxyAdmin(address _proxyAdmin) public onlyOwner { + require(_proxyAdmin != address(0), "Invalid Address"); + proxyAdmin = _proxyAdmin; + emit ProxyAdminUpdated(_proxyAdmin); } /** @dev Create a new multisig wallet for an endowment @@ -100,7 +100,7 @@ contract EndowmentMultiSigFactory is Ownable { false, transactionExpiry ); - wallet = address(new ProxyContract(IMPLEMENTATION_ADDRESS, PROXY_ADMIN, EndowmentData)); + wallet = address(new ProxyContract(implementationAddress, proxyAdmin, EndowmentData)); IEndowmentMultiSigEmitter(emitterAddress).createEndowmentMultisig( wallet, endowmentId, diff --git a/contracts/multisigs/endowment-multisig/scripts/deploy.ts b/contracts/multisigs/endowment-multisig/scripts/deploy.ts index 0cf6fab53..be8f156f1 100644 --- a/contracts/multisigs/endowment-multisig/scripts/deploy.ts +++ b/contracts/multisigs/endowment-multisig/scripts/deploy.ts @@ -1,14 +1,18 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import { EndowmentMultiSigEmitter__factory, EndowmentMultiSigFactory__factory, EndowmentMultiSig__factory, ProxyContract__factory, } from "typechain-types"; -import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; export async function deployEndowmentMultiSig( registrar: string, + proxyAdmin: string, + factoryOwner: string, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{ emitter: { @@ -20,11 +24,9 @@ export async function deployEndowmentMultiSig( }> { logger.out("Deploying EndowmentMultiSig contracts..."); - const {proxyAdmin} = await getSigners(hre); - // deploy implementation contract logger.out("Deploying EndowmentMultiSig implementation..."); - const endowmentMultiSigFactory = new EndowmentMultiSig__factory(proxyAdmin); + const endowmentMultiSigFactory = new EndowmentMultiSig__factory(deployer); const endowmentMultiSig = await endowmentMultiSigFactory.deploy(); await endowmentMultiSig.deployed(); logger.out(`Address: ${endowmentMultiSig.address}`); @@ -33,19 +35,24 @@ export async function deployEndowmentMultiSig( logger.out("Deploying EndowmentMultiSigFactory..."); const factoryCtorArgs: Parameters = [ endowmentMultiSig.address, - proxyAdmin.address, + proxyAdmin, registrar, ]; - const EndowmentMultiSigFactoryFactory = new EndowmentMultiSigFactory__factory(proxyAdmin); + const EndowmentMultiSigFactoryFactory = new EndowmentMultiSigFactory__factory(deployer); const EndowmentMultiSigFactory = await EndowmentMultiSigFactoryFactory.deploy(...factoryCtorArgs); await EndowmentMultiSigFactory.deployed(); logger.out(`Address: ${EndowmentMultiSigFactory.address}`); + logger.out(`Transferring ownership to: ${factoryOwner}...`); + const tx = await EndowmentMultiSigFactory.transferOwnership(factoryOwner); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); + // deploy emitter logger.out("Deploying EndowmentMultiSigEmitter..."); logger.out("Deploying implementation..."); - const emitterFactory = new EndowmentMultiSigEmitter__factory(proxyAdmin); + const emitterFactory = new EndowmentMultiSigEmitter__factory(deployer); const emitter = await emitterFactory.deploy(); await emitter.deployed(); logger.out(`Address: ${emitter.address}`); @@ -54,8 +61,8 @@ export async function deployEndowmentMultiSig( const initData = emitter.interface.encodeFunctionData("initEndowmentMultiSigEmitter", [ EndowmentMultiSigFactory.address, ]); - const proxyFactory = new ProxyContract__factory(proxyAdmin); - const emitterProxy = await proxyFactory.deploy(emitter.address, proxyAdmin.address, initData); + const proxyFactory = new ProxyContract__factory(deployer); + const emitterProxy = await proxyFactory.deploy(emitter.address, proxyAdmin, initData); await emitterProxy.deployed(); logger.out(`Address: ${emitterProxy.address}`); diff --git a/contracts/multisigs/scripts/deploy.ts b/contracts/multisigs/scripts/deploy.ts index c745c8c0d..cd8398a0b 100644 --- a/contracts/multisigs/scripts/deploy.ts +++ b/contracts/multisigs/scripts/deploy.ts @@ -1,2 +1,3 @@ export * from "./deployAPTeamMultiSig"; export * from "./deployCharityApplications"; +export * from "./deployProxyAdminMultiSig"; diff --git a/contracts/multisigs/scripts/deployAPTeamMultiSig.ts b/contracts/multisigs/scripts/deployAPTeamMultiSig.ts index fa8d2b652..025a6555c 100644 --- a/contracts/multisigs/scripts/deployAPTeamMultiSig.ts +++ b/contracts/multisigs/scripts/deployAPTeamMultiSig.ts @@ -1,19 +1,27 @@ import config from "config"; import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, ProxyContract__factory} from "typechain-types"; import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; -export async function deployAPTeamMultiSig(hre: HardhatRuntimeEnvironment): Promise<{ +export async function deployAPTeamMultiSig( + proxyAdmin: string, + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise<{ implementation: Deployment; proxy: Deployment; }> { logger.out("Deploying APTeamMultiSig..."); - const {apTeamMultisigOwners, proxyAdmin} = await getSigners(hre); + const {apTeamMultisigOwners} = await getSigners(hre); + const owners = apTeamMultisigOwners + ? apTeamMultisigOwners.map((x) => x.address) + : config.PROD_CONFIG.APTeamMultiSigOwners; // deploy implementation logger.out("Deploying implementation..."); - const apTeamMultiSigFactory = new APTeamMultiSig__factory(proxyAdmin); + const apTeamMultiSigFactory = new APTeamMultiSig__factory(deployer); const apTeamMultiSig = await apTeamMultiSigFactory.deploy(); await apTeamMultiSig.deployed(); logger.out(`Address: ${apTeamMultiSig.address}.`); @@ -21,15 +29,15 @@ export async function deployAPTeamMultiSig(hre: HardhatRuntimeEnvironment): Prom // deploy proxy logger.out("Deploying proxy..."); const apTeamMultiSigData = apTeamMultiSig.interface.encodeFunctionData("initializeAPTeam", [ - apTeamMultisigOwners.map((x) => x.address), + owners, config.AP_TEAM_MULTISIG_DATA.threshold, config.AP_TEAM_MULTISIG_DATA.requireExecution, config.AP_TEAM_MULTISIG_DATA.transactionExpiry, ]); - const proxyFactory = new ProxyContract__factory(proxyAdmin); + const proxyFactory = new ProxyContract__factory(deployer); const apTeamMultiSigProxy = await proxyFactory.deploy( apTeamMultiSig.address, - proxyAdmin.address, + proxyAdmin, apTeamMultiSigData ); await apTeamMultiSigProxy.deployed(); diff --git a/contracts/multisigs/scripts/deployCharityApplications.ts b/contracts/multisigs/scripts/deployCharityApplications.ts index 19c59242c..a3984b209 100644 --- a/contracts/multisigs/scripts/deployCharityApplications.ts +++ b/contracts/multisigs/scripts/deployCharityApplications.ts @@ -1,23 +1,29 @@ import config from "config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {HardhatRuntimeEnvironment} from "hardhat/types"; import {CharityApplications__factory, ProxyContract__factory} from "typechain-types"; import {Deployment, getContractName, getSigners, logger, updateAddresses} from "utils"; export async function deployCharityApplications( accountsDiamond: string, + proxyAdmin: string, seedAsset: string, + deployer: SignerWithAddress, hre: HardhatRuntimeEnvironment ): Promise<{ implementation: Deployment; proxy: Deployment; }> { - const {apTeamMultisigOwners, proxyAdmin} = await getSigners(hre); - logger.out("Deploying CharityApplications..."); + const {charityApplicationsOwners} = await getSigners(hre); + const owners = !charityApplicationsOwners + ? config.PROD_CONFIG.CharityApplicationsOwners + : charityApplicationsOwners.map((x) => x.address); + // deploy implementation logger.out("Deploying implementation..."); - const charityApplicationsFactory = new CharityApplications__factory(proxyAdmin); + const charityApplicationsFactory = new CharityApplications__factory(deployer); const charityApplications = await charityApplicationsFactory.deploy(); await charityApplications.deployed(); logger.out(`Address: ${charityApplications.address}`); @@ -25,7 +31,7 @@ export async function deployCharityApplications( // deploy proxy logger.out("Deploying proxy..."); const initData = charityApplications.interface.encodeFunctionData("initializeApplications", [ - apTeamMultisigOwners.map((x) => x.address), + owners, config.CHARITY_APPLICATIONS_DATA.threshold, config.CHARITY_APPLICATIONS_DATA.requireExecution, config.CHARITY_APPLICATIONS_DATA.transactionExpiry, @@ -35,10 +41,10 @@ export async function deployCharityApplications( seedAsset, config.CHARITY_APPLICATIONS_DATA.seedAmount, ]); - const proxyFactory = new ProxyContract__factory(proxyAdmin); + const proxyFactory = new ProxyContract__factory(deployer); const charityApplicationsProxy = await proxyFactory.deploy( charityApplications.address, - proxyAdmin.address, + proxyAdmin, initData ); await charityApplicationsProxy.deployed(); diff --git a/contracts/multisigs/scripts/deployProxyAdminMultiSig.ts b/contracts/multisigs/scripts/deployProxyAdminMultiSig.ts new file mode 100644 index 000000000..7a1d5986c --- /dev/null +++ b/contracts/multisigs/scripts/deployProxyAdminMultiSig.ts @@ -0,0 +1,35 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import config from "config"; +import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {ProxyAdminMultiSig__factory} from "typechain-types"; +import {Deployment, getContractName, logger, updateAddresses} from "utils"; + +export async function deployProxyAdminMultisig( + owners: string[], + deployer: SignerWithAddress, + hre: HardhatRuntimeEnvironment +): Promise { + logger.out("Deploying ProxyAdmin multisig..."); + + const constructorArguments: Parameters = [ + owners, + config.PROXY_ADMIN_MULTISIG_DATA.threshold, + config.PROXY_ADMIN_MULTISIG_DATA.requireExecution, + config.PROXY_ADMIN_MULTISIG_DATA.transactionExpiry, + ]; + + const proxyAdminFactory = new ProxyAdminMultiSig__factory(deployer); + const proxyAdmin = await proxyAdminFactory.deploy(...constructorArguments); + logger.out(`Tx hash: ${proxyAdmin.deployTransaction.hash}`); + await proxyAdmin.deployed(); + logger.out(`Address: ${proxyAdmin.address}.`); + + // update address file & verify contracts + await updateAddresses({multiSig: {proxyAdmin: proxyAdmin.address}}, hre); + + return { + address: proxyAdmin.address, + contractName: getContractName(proxyAdminFactory), + constructorArguments: constructorArguments, + }; +} diff --git a/hardhat.config.ts b/hardhat.config.ts index 186aa1265..4897713f0 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,6 +1,6 @@ import {HardhatUserConfig} from "hardhat/config"; import {HardhatNetworkAccountsUserConfig} from "hardhat/types"; -import {envConfig, getHardhatAccounts} from "./utils"; +import {envConfigDev, envConfigProd, getHardhatAccounts} from "./utils"; import "@nomiclabs/hardhat-etherscan"; import "@nomicfoundation/hardhat-chai-matchers"; import "@openzeppelin/hardhat-upgrades"; @@ -10,14 +10,7 @@ require("tsconfig-paths/register"); // must use `require`, otherwise TS complain import "./tasks"; import * as tdly from "@tenderly/hardhat-tenderly"; -var accounts = [ - envConfig.DEPLOYER.key, - envConfig.PROXY_ADMIN.key, - envConfig.AP_TEAM_1.key, - envConfig.AP_TEAM_2.key, - envConfig.AP_TEAM_3.key, -]; -var hardhatAccounts: HardhatNetworkAccountsUserConfig = getHardhatAccounts(accounts); +var hardhatAccounts: HardhatNetworkAccountsUserConfig = getHardhatAccounts(envConfigDev.ACCOUNTS); tdly.setup({ automaticVerifications: false, @@ -42,21 +35,20 @@ const config: HardhatUserConfig = { }, networks: { mainnet: { - url: envConfig.MAINNET_RPC_URL, - accounts: accounts, + url: envConfigProd.MAINNET_RPC_URL, + accounts: envConfigProd.ACCOUNTS, }, goerli: { - url: envConfig.GOERLI_RPC_URL, - accounts: accounts, + url: envConfigDev.GOERLI_RPC_URL, + accounts: envConfigDev.ACCOUNTS, }, mumbai: { - url: envConfig.MUMBAI_RPC_URL, - accounts: accounts, - // gasPrice: 50_000_000_000 //50Gwei + url: envConfigDev.MUMBAI_RPC_URL, + accounts: envConfigDev.ACCOUNTS, }, polygon: { - url: envConfig.POLYGON_RPC_URL, - accounts: accounts, + url: envConfigProd.POLYGON_RPC_URL, + accounts: envConfigProd.ACCOUNTS, }, hardhat: { accounts: hardhatAccounts, @@ -67,10 +59,10 @@ const config: HardhatUserConfig = { }, etherscan: { apiKey: { - mainnet: envConfig.ETHERSCAN_API_KEY, - goerli: envConfig.ETHERSCAN_API_KEY, - polygon: envConfig.POLYSCAN_API_KEY, - polygonMumbai: envConfig.POLYSCAN_API_KEY, + mainnet: envConfigProd.ETHERSCAN_API_KEY, + goerli: envConfigDev.ETHERSCAN_API_KEY, + polygon: envConfigProd.POLYSCAN_API_KEY, + polygonMumbai: envConfigDev.POLYSCAN_API_KEY, }, }, tenderly: { diff --git a/tasks/deploy/deployAPTeamMultiSig.ts b/tasks/deploy/deployAPTeamMultiSig.ts index 643eb49b8..78397625c 100644 --- a/tasks/deploy/deployAPTeamMultiSig.ts +++ b/tasks/deploy/deployAPTeamMultiSig.ts @@ -1,18 +1,26 @@ import {deployAPTeamMultiSig} from "contracts/multisigs/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, isLocalNetwork, logger, verify} from "utils"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; task("deploy:APTeamMultiSig", "Will deploy APTeamMultiSig contract") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { + .addOptionalParam("admin", "override for proxy admin wallet, default: proxyAdminMultisig") + .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean; admin?: string}, hre) => { try { const isConfirmed = taskArgs.yes || (await confirmAction("Deploying APTeamMultiSig...")); if (!isConfirmed) { return logger.out("Confirmation denied.", logger.Level.Warn); } - const deployments = await deployAPTeamMultiSig(hre); + const {deployer} = await getSigners(hre); + let deployments; + if (taskArgs.admin) { + deployments = await deployAPTeamMultiSig(taskArgs.admin, deployer, hre); + } else { + const addresses = await getAddresses(hre); + deployments = await deployAPTeamMultiSig(addresses.multiSig.proxyAdmin, deployer, hre); + } await hre.run("manage:registrar:transferOwnership", { to: deployments.proxy.address, diff --git a/tasks/deploy/deployAccountsDiamond.ts b/tasks/deploy/deployAccountsDiamond.ts index b1959cc71..56b65d0ca 100644 --- a/tasks/deploy/deployAccountsDiamond.ts +++ b/tasks/deploy/deployAccountsDiamond.ts @@ -1,6 +1,6 @@ import {deployAccountsDiamond} from "contracts/core/accounts/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, isLocalNetwork, logger, verify} from "utils"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; type TaskArgs = { apTeamMultisig?: string; @@ -28,10 +28,17 @@ task("deploy:accounts", "It will deploy accounts diamond contracts") } const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); const apTeam = taskArgs.apTeamMultisig || addresses.multiSig.apTeam.proxy; const registrar = taskArgs.registrar || addresses.registrar.proxy; - const {diamond, facets} = await deployAccountsDiamond(apTeam, registrar, hre); + const {diamond, facets} = await deployAccountsDiamond( + apTeam, + registrar, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); await hre.run("manage:registrar:updateConfig", { accountsContract: diamond.address, diff --git a/tasks/deploy/deployAngelProtocol.ts b/tasks/deploy/deployAngelProtocol.ts index 36bdd92c9..105293eb5 100644 --- a/tasks/deploy/deployAngelProtocol.ts +++ b/tasks/deploy/deployAngelProtocol.ts @@ -1,33 +1,45 @@ +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import config from "config"; +import {deployAccountsDiamond} from "contracts/core/accounts/scripts/deploy"; +import {deployGasFwd} from "contracts/core/gasFwd/scripts/deploy"; +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 { + deployAPTeamMultiSig, + deployCharityApplications, + deployProxyAdminMultisig, +} from "contracts/multisigs/scripts/deploy"; import {task} from "hardhat/config"; import { ADDRESS_ZERO, Deployment, confirmAction, + connectSignerFromPkey, getSigners, isLocalNetwork, logger, - resetAddresses, + resetContractAddresses, verify, } from "utils"; - -import {deployAccountsDiamond} from "contracts/core/accounts/scripts/deploy"; -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 {deployEndowmentMultiSig} from "contracts/multisigs/endowment-multisig/scripts/deploy"; -import {deployAPTeamMultiSig, deployCharityApplications} from "contracts/multisigs/scripts/deploy"; -// import {deployEmitters} from "contracts/normalized_endowment/scripts/deployEmitter"; -// import {deployImplementation} from "contracts/normalized_endowment/scripts/deployImplementation"; - -import {deployGasFwd} from "contracts/core/gasFwd/scripts/deploy"; -import {deployVaultEmitter} from "contracts/core/vault/scripts/deployVaultEmitter"; import {getOrDeployThirdPartyContracts, updateRegistrarNetworkConnections} from "../helpers"; +type TaskArgs = { + skipVerify: boolean; + yes: boolean; + apTeamSignerPkey?: string; +}; + task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) + .setAction(async (taskArgs: TaskArgs, hre) => { try { const isConfirmed = taskArgs.yes || (await confirmAction("Deploying all Angel Protocol contracts...")); @@ -37,15 +49,39 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") const verify_contracts = !isLocalNetwork(hre) && !taskArgs.skipVerify; - const {deployer, proxyAdmin, treasury} = await getSigners(hre); + let {deployer, proxyAdminMultisigOwners, apTeamMultisigOwners, treasury} = await getSigners( + hre + ); - await resetAddresses(hre); + let treasuryAddress = treasury ? treasury.address : config.PROD_CONFIG.Treasury; - logger.out(`Deploying the contracts with the account: ${proxyAdmin.address}`); + const proxyAdminMultisigOwnerAddresses = proxyAdminMultisigOwners + ? proxyAdminMultisigOwners.map((x) => x.address) + : config.PROD_CONFIG.ProxyAdminMultiSigOwners; + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } - const thirdPartyAddresses = await getOrDeployThirdPartyContracts(proxyAdmin, hre); + // Reset the contract address object for all contracts that will be deployed here + await resetContractAddresses(hre); + + logger.out(`Deploying the contracts with the account: ${deployer.address}`); + + const proxyAdminMultisig = await deployProxyAdminMultisig( + proxyAdminMultisigOwnerAddresses, + deployer, + hre + ); - const apTeamMultisig = await deployAPTeamMultiSig(hre); + const thirdPartyAddresses = await getOrDeployThirdPartyContracts(deployer, hre); + + const apTeamMultisig = await deployAPTeamMultiSig(proxyAdminMultisig.address, deployer, hre); const registrar = await deployRegistrar( { @@ -54,25 +90,34 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") router: ADDRESS_ZERO, owner: apTeamMultisig.proxy.address, deployer, - proxyAdmin, - treasury: treasury.address, + proxyAdmin: proxyAdminMultisig.address, + treasury: treasuryAddress, apTeamMultisig: apTeamMultisig.proxy.address, }, hre ); // Router deployment will require updating Registrar config's "router" address - const router = await deployRouter(registrar.proxy.address, hre); + const router = await deployRouter( + registrar.proxy.address, + proxyAdminMultisig.address, + deployer, + hre + ); const accounts = await deployAccountsDiamond( apTeamMultisig.proxy.address, registrar.proxy.address, + proxyAdminMultisig.address, + deployer, hre ); const gasFwd = await deployGasFwd( { - admin: proxyAdmin, + deployer: deployer, + proxyAdmin: proxyAdminMultisig.address, + factoryOwner: apTeamMultisig.proxy.address, registrar: registrar.proxy.address, }, hre @@ -82,31 +127,41 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") const charityApplications = await deployCharityApplications( accounts.diamond.address, + proxyAdminMultisig.address, thirdPartyAddresses.seedAsset.address, + deployer, hre ); const indexFund = await deployIndexFund( registrar.proxy.address, apTeamMultisig.proxy.address, + proxyAdminMultisig.address, + deployer, hre ); - const endowmentMultiSig = await deployEndowmentMultiSig(registrar.proxy.address, hre); + const endowmentMultiSig = await deployEndowmentMultiSig( + registrar.proxy.address, + proxyAdminMultisig.address, + apTeamMultisig.proxy.address, + deployer, + hre + ); - const vaultEmitter = await deployVaultEmitter(hre); + const vaultEmitter = await deployVaultEmitter(proxyAdminMultisig.address, deployer, hre); await hre.run("manage:registrar:updateConfig", { accountsContract: accounts.diamond.address, //Address collectorShare: config.REGISTRAR_UPDATE_CONFIG.collectorShare, //uint256 indexFundContract: indexFund.proxy.address, //address - treasury: treasury.address, + treasury: treasuryAddress, uniswapRouter: thirdPartyAddresses.uniswap.swapRouter.address, //address uniswapFactory: thirdPartyAddresses.uniswap.factory.address, //address multisigFactory: endowmentMultiSig.factory.address, //address multisigEmitter: endowmentMultiSig.emitter.proxy.address, //address charityApplications: charityApplications.proxy.address, //address - proxyAdmin: proxyAdmin.address, //address + proxyAdmin: proxyAdminMultisig.address, //address usdcAddress: thirdPartyAddresses.usdcToken.address, wMaticAddress: thirdPartyAddresses.wmaticToken.address, gasFwdFactory: gasFwd.factory.address, @@ -122,6 +177,7 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") registrar.proxy.address, apTeamMultisig.proxy.address, {router: router.proxy.address}, + apTeamSigner, hre ); @@ -129,6 +185,7 @@ task("deploy:AngelProtocol", "Will deploy complete Angel Protocol") const deployments: Array = [ apTeamMultisig.implementation, apTeamMultisig.proxy, + proxyAdminMultisig, registrar.implementation, registrar.proxy, router.implementation, diff --git a/tasks/deploy/deployCharityApplications.ts b/tasks/deploy/deployCharityApplications.ts index b9934dc73..9f682457c 100644 --- a/tasks/deploy/deployCharityApplications.ts +++ b/tasks/deploy/deployCharityApplications.ts @@ -1,6 +1,6 @@ import {deployCharityApplications} from "contracts/multisigs/scripts/deployCharityApplications"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, isLocalNetwork, logger, verify} from "utils"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; type TaskArgs = { accountsDiamond?: string; @@ -24,12 +24,15 @@ task("deploy:CharityApplications", "Will deploy CharityApplication contract") } const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); const accountsDiamond = taskArgs.accountsDiamond || addresses.accounts.diamond; const charityApplications = await deployCharityApplications( accountsDiamond, + addresses.multiSig.proxyAdmin, addresses.tokens.seedAsset, + deployer, hre ); diff --git a/tasks/deploy/deployEndowmentMultisig.ts b/tasks/deploy/deployEndowmentMultisig.ts index 58a728e2a..ec0d9f555 100644 --- a/tasks/deploy/deployEndowmentMultisig.ts +++ b/tasks/deploy/deployEndowmentMultisig.ts @@ -1,6 +1,6 @@ import {deployEndowmentMultiSig} from "contracts/multisigs/endowment-multisig/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, isLocalNetwork, getAddresses, logger, verify} from "utils"; +import {confirmAction, isLocalNetwork, getAddresses, logger, verify, getSigners} from "utils"; type TaskArgs = { registrar?: string; @@ -18,6 +18,7 @@ task("deploy:EndowmentMultiSig", "Will deploy EndowmentMultiSig contract") .setAction(async (taskArgs: TaskArgs, hre) => { try { const addresses = await getAddresses(hre); + const {deployer} = await getSigners(hre); const registrarAddress = taskArgs.registrar || addresses.registrar.proxy; @@ -26,7 +27,13 @@ task("deploy:EndowmentMultiSig", "Will deploy EndowmentMultiSig contract") return logger.out("Confirmation denied.", logger.Level.Warn); } - const deployData = await deployEndowmentMultiSig(registrarAddress, hre); + const deployData = await deployEndowmentMultiSig( + registrarAddress, + addresses.multiSig.proxyAdmin, + addresses.multiSig.apTeam.proxy, + deployer, + hre + ); await hre.run("manage:registrar:updateConfig", { multisigFactory: deployData.factory.address, diff --git a/tasks/deploy/deployGasFwd.ts b/tasks/deploy/deployGasFwd.ts index 12fa9d0d4..9d425a55b 100644 --- a/tasks/deploy/deployGasFwd.ts +++ b/tasks/deploy/deployGasFwd.ts @@ -1,20 +1,33 @@ import {deployGasFwd} from "contracts/core/gasFwd/scripts/deploy"; import {task} from "hardhat/config"; -import {getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; type TaskArgs = { skipVerify: boolean; + yes: boolean; }; task("deploy:GasFwd", "Will deploy the GasFwd implementation and factory") .addFlag("skipVerify", "Skip contract verification") + .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { const addresses = await getAddresses(hre); - const {proxyAdmin} = await getSigners(hre); + const {deployer} = await getSigners(hre); + + const isConfirmed = + taskArgs.yes || (await confirmAction("Deploying GasFwd and GasFwdFactory.")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } const gasFwdDeployment = await deployGasFwd( - {admin: proxyAdmin, registrar: addresses.registrar.proxy}, + { + deployer: deployer, + proxyAdmin: addresses.multiSig.proxyAdmin, + factoryOwner: addresses.multiSig.apTeam.proxy, + registrar: addresses.registrar.proxy, + }, hre ); diff --git a/tasks/deploy/deployGiftcard.ts b/tasks/deploy/deployGiftcard.ts index 067ba481f..32ffef8e0 100644 --- a/tasks/deploy/deployGiftcard.ts +++ b/tasks/deploy/deployGiftcard.ts @@ -1,4 +1,4 @@ -import {deployGiftCard} from "contracts/accessory/gift-cards/scripts/deploy"; +import {deployGiftCard} from "contracts/accessory/gift-cards/scripts/deploy.ts"; import {task} from "hardhat/config"; import {getAddresses, isLocalNetwork, logger} from "utils"; diff --git a/tasks/deploy/deployIndexFund.ts b/tasks/deploy/deployIndexFund.ts index 9f699ce25..5b29bb2bf 100644 --- a/tasks/deploy/deployIndexFund.ts +++ b/tasks/deploy/deployIndexFund.ts @@ -1,6 +1,6 @@ import {deployIndexFund} from "contracts/core/index-fund/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, isLocalNetwork, logger, verify} from "utils"; +import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; type TaskArgs = { owner?: string; @@ -27,12 +27,19 @@ task("deploy:IndexFund", "Will deploy IndexFund contract") return logger.out("Confirmation denied.", logger.Level.Warn); } + const {deployer} = await getSigners(hre); const addresses = await getAddresses(hre); const registrar = taskArgs.registrar || addresses.registrar.proxy; const owner = taskArgs.owner || addresses.multiSig.apTeam.proxy; - const deployment = await deployIndexFund(registrar, owner, hre); + const deployment = await deployIndexFund( + registrar, + owner, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); await hre.run("manage:registrar:updateConfig", { indexFundContract: deployment.proxy.address, diff --git a/tasks/deploy/deployLocalRegistrar.ts b/tasks/deploy/deployLocalRegistrar.ts index 3a654d280..f8c53fea7 100644 --- a/tasks/deploy/deployLocalRegistrar.ts +++ b/tasks/deploy/deployLocalRegistrar.ts @@ -1,18 +1,32 @@ import {deployLocalRegistrar} from "contracts/core/registrar/scripts/deploy"; import {deployRouter} from "contracts/core/router/scripts/deploy"; import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; -import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + isLocalNetwork, + logger, + verify, +} from "utils"; import {updateRegistrarNetworkConnections} from "../helpers"; type TaskArgs = { skipVerify: boolean; + apTeamSignerPkey?: string; yes: boolean; owner?: string; }; task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract and Router.") .addOptionalParam("owner", "The owner wallet for both router and registrar") + .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) => { @@ -23,7 +37,17 @@ task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract return logger.out("Confirmation denied.", logger.Level.Warn); } - const {proxyAdmin, deployer} = await getSigners(hre); + const {deployer, apTeamMultisigOwners} = await getSigners(hre); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const addresses = await getAddresses(hre); const owner = taskArgs.owner || addresses.multiSig.apTeam.proxy; @@ -31,8 +55,8 @@ task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract const localRegistrar = await deployLocalRegistrar( { owner: owner, - deployer, - proxyAdmin, + deployer: deployer, + proxyAdmin: addresses.multiSig.proxyAdmin, }, hre ); @@ -41,7 +65,12 @@ task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract return; } - const router = await deployRouter(localRegistrar.proxy.address, hre); + const router = await deployRouter( + localRegistrar.proxy.address, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); let network = await hre.ethers.provider.getNetwork(); const networkInfo: LocalRegistrarLib.NetworkInfoStruct = { @@ -55,6 +84,7 @@ task("deploy:LocalRegistrarAndRouter", "Will deploy the Local Registrar contract localRegistrar.proxy.address, owner, networkInfo, + apTeamSigner, hre ); diff --git a/tasks/deploy/deployRegistrar.ts b/tasks/deploy/deployRegistrar.ts index 3049cd4a3..baf442b15 100644 --- a/tasks/deploy/deployRegistrar.ts +++ b/tasks/deploy/deployRegistrar.ts @@ -2,12 +2,22 @@ import config from "config"; import {deployRegistrar} from "contracts/core/registrar/scripts/deploy"; import {deployRouter} from "contracts/core/router/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + isLocalNetwork, + logger, + verify, +} from "utils"; import {updateRegistrarNetworkConnections} from "../helpers"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; type TaskArgs = { apTeamMultisig?: string; router?: string; + apTeamSignerPkey?: string; skipVerify: boolean; yes: boolean; }; @@ -24,6 +34,10 @@ task( "router", "Router contract address. 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) => { @@ -34,7 +48,19 @@ task( return logger.out("Confirmation denied.", logger.Level.Warn); } - const {treasury, proxyAdmin, deployer} = await getSigners(hre); + const {treasury, deployer, apTeamMultisigOwners} = await getSigners(hre); + + let treasuryAddress = treasury ? treasury.address : config.PROD_CONFIG.Treasury; + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const addresses = await getAddresses(hre); const apTeamMultiSig = taskArgs.apTeamMultisig || addresses.multiSig.apTeam.proxy; @@ -47,8 +73,8 @@ task( router: oldRouterAddress, owner: apTeamMultiSig, deployer, - proxyAdmin, - treasury: treasury.address, + proxyAdmin: addresses.multiSig.proxyAdmin, + treasury: treasuryAddress, apTeamMultisig: apTeamMultiSig, }, hre @@ -59,13 +85,13 @@ task( collectorShare: config.REGISTRAR_UPDATE_CONFIG.collectorShare, gasFwdFactory: addresses.gasFwd.factory, indexFundContract: addresses.indexFund.proxy, - treasury: treasury.address, + treasury: treasuryAddress, uniswapRouter: addresses.uniswap.swapRouter, uniswapFactory: addresses.uniswap.factory, multisigFactory: addresses.multiSig.endowment.factory, multisigEmitter: addresses.multiSig.endowment.emitter.proxy, charityApplications: addresses.multiSig.charityApplications.proxy, - proxyAdmin: proxyAdmin.address, + proxyAdmin: addresses.multiSig.proxyAdmin, usdcAddress: addresses.tokens.usdc, wMaticAddress: addresses.tokens.wmatic, yes: true, @@ -76,13 +102,19 @@ task( yes: true, }); - const router = await deployRouter(registrar.proxy.address, hre); + const router = await deployRouter( + registrar.proxy.address, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); // Registrar NetworkInfo's Router address must be updated for the current network await updateRegistrarNetworkConnections( registrar.proxy.address, apTeamMultiSig, {router: router.proxy.address}, + apTeamSigner, hre ); diff --git a/tasks/deploy/deployRouter.ts b/tasks/deploy/deployRouter.ts index d0c8d60ab..54c44ce5d 100644 --- a/tasks/deploy/deployRouter.ts +++ b/tasks/deploy/deployRouter.ts @@ -1,11 +1,21 @@ import {deployRouter} from "contracts/core/router/scripts/deploy"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, isLocalNetwork, logger, verify} from "utils"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + isLocalNetwork, + logger, + verify, +} from "utils"; import {updateRegistrarNetworkConnections} from "../helpers"; type TaskArgs = { apTeamMultisig?: string; registrar?: string; + apTeamSignerPkey?: string; skipVerify: boolean; yes: boolean; }; @@ -19,6 +29,10 @@ task("deploy:Router", "Will deploy Router contract") "registrar", "Registrar contract address. 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) => { @@ -29,17 +43,33 @@ task("deploy:Router", "Will deploy Router contract") } const addresses = await getAddresses(hre); + const {apTeamMultisigOwners, deployer} = await getSigners(hre); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } const apTeamMultiSig = taskArgs.apTeamMultisig || addresses.multiSig.apTeam.proxy; const registrar = taskArgs.registrar || addresses.registrar.proxy; - const deployment = await deployRouter(registrar, hre); + const deployment = await deployRouter( + registrar, + addresses.multiSig.proxyAdmin, + deployer, + hre + ); // Registrar NetworkInfo's Router address must be updated for the current network await updateRegistrarNetworkConnections( registrar, apTeamMultiSig, {router: deployment.proxy.address}, + apTeamSigner, hre ); diff --git a/tasks/deploy/deploySideChain.ts b/tasks/deploy/deploySideChain.ts index 3245a499e..e6148b855 100644 --- a/tasks/deploy/deploySideChain.ts +++ b/tasks/deploy/deploySideChain.ts @@ -1,7 +1,15 @@ +import config from "config"; +import {deployAPTeamMultiSig, deployProxyAdminMultisig} from "contracts/multisigs/scripts/deploy"; import {task} from "hardhat/config"; -import {Deployment, confirmAction, isLocalNetwork, logger, verify} from "utils"; -import {getSigners, resetAddresses} from "utils"; -import {deployAPTeamMultiSig} from "contracts/multisigs/scripts/deploy"; +import { + Deployment, + confirmAction, + getSigners, + isLocalNetwork, + logger, + resetContractAddresses, + verify, +} from "utils"; task("deploy:SideChain", "Will deploy complete side-chain infrastructure") .addFlag("skipVerify", "Skip contract verification") @@ -16,13 +24,23 @@ task("deploy:SideChain", "Will deploy complete side-chain infrastructure") const verify_contracts = !isLocalNetwork(hre) && !taskArgs.skipVerify; - const {deployer} = await getSigners(hre); + let {deployer, proxyAdminMultisigOwners} = await getSigners(hre); - await resetAddresses(hre); + const proxyAdminMultisigOwnerAddresses = proxyAdminMultisigOwners + ? proxyAdminMultisigOwners.map((x) => x.address) + : config.PROD_CONFIG.ProxyAdminMultiSigOwners; + + await resetContractAddresses(hre); logger.out(`Deploying the contracts with the account: ${deployer.address}`); - const apTeamMultisig = await deployAPTeamMultiSig(hre); + const proxyAdminMultisig = await deployProxyAdminMultisig( + proxyAdminMultisigOwnerAddresses, + deployer, + hre + ); + + const apTeamMultisig = await deployAPTeamMultiSig(proxyAdminMultisig.address, deployer, hre); await hre.run("deploy:LocalRegistrarAndRouter", { skipVerify: verify_contracts, @@ -31,15 +49,14 @@ task("deploy:SideChain", "Will deploy complete side-chain infrastructure") }); if (verify_contracts) { - const deployments: Array = [ + const deployments: Array = [ + proxyAdminMultisig, apTeamMultisig.implementation, apTeamMultisig.proxy, ]; for (const deployment of deployments) { - if (deployment) { - await verify(hre, deployment); - } + await verify(hre, deployment); } } diff --git a/tasks/helpers/updateRegistrar.ts b/tasks/helpers/updateRegistrar.ts index 7609a56d2..c02e76db3 100644 --- a/tasks/helpers/updateRegistrar.ts +++ b/tasks/helpers/updateRegistrar.ts @@ -1,11 +1,11 @@ import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, Registrar__factory} from "typechain-types"; import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; import { NetworkConnectionAction, getAxlNetworkName, getNetworkNameFromChainId, - getSigners, logger, structToObject, validateAddress, @@ -15,6 +15,7 @@ export async function updateRegistrarNetworkConnections( registrar = "", apTeamMultisig = "", networkInfo: Partial, + signer: SignerWithAddress, hre: HardhatRuntimeEnvironment ) { logger.divider(); @@ -34,9 +35,7 @@ export async function updateRegistrarNetworkConnections( validateAddress(registrar, "registrar"); validateAddress(apTeamMultisig, "apTeamMultisig"); - const {apTeamMultisigOwners} = await getSigners(hre); - - const registrarContract = Registrar__factory.connect(registrar, apTeamMultisigOwners[0]); + const registrarContract = Registrar__factory.connect(registrar, signer); logger.out("Fetching current Registrar's network connection data..."); @@ -51,10 +50,7 @@ export async function updateRegistrarNetworkConnections( "updateNetworkConnections", [networkName, {...curNetworkConnection, ...networkInfo}, NetworkConnectionAction.POST] ); - const apTeamMultisigContract = APTeamMultiSig__factory.connect( - apTeamMultisig, - apTeamMultisigOwners[0] - ); + const apTeamMultisigContract = APTeamMultiSig__factory.connect(apTeamMultisig, signer); const tx = await apTeamMultisigContract.submitTransaction( registrarContract.address, 0, diff --git a/tasks/manage/accounts/updateConfig.ts b/tasks/manage/accounts/updateConfig.ts index 8966ee477..82194829e 100644 --- a/tasks/manage/accounts/updateConfig.ts +++ b/tasks/manage/accounts/updateConfig.ts @@ -1,13 +1,22 @@ -import {task, types} from "hardhat/config"; +import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import { APTeamMultiSig__factory, AccountsQueryEndowments__factory, AccountsUpdate__factory, } from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + logger, + structToObject, +} from "utils"; type TaskArgs = { registrarContract?: string; + apTeamSignerPkey?: string; yes: boolean; }; @@ -16,25 +25,36 @@ task("manage:accounts:updateConfig", "Will update Accounts Diamond config") "registrarContract", "Registrar contract address. 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("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { - const {yes, ...newConfig} = taskArgs; - logger.divider(); const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + logger.out("Querying current config..."); const accountsQueryEndowments = AccountsQueryEndowments__factory.connect( addresses.accounts.diamond, - apTeamMultisigOwners[0] + apTeamSigner ); const curConfig = await accountsQueryEndowments.queryConfig(); - logger.out(curConfig); + logger.out(structToObject(curConfig)); logger.out("Config data to update:"); - logger.out(newConfig); + logger.out({registrarContract: taskArgs.registrarContract}); const isConfirmed = taskArgs.yes || (await confirmAction(`Updating config...`)); if (!isConfirmed) { @@ -44,14 +64,14 @@ task("manage:accounts:updateConfig", "Will update Accounts Diamond config") logger.out("Updating config..."); const accountsUpdate = AccountsUpdate__factory.connect( addresses.accounts.diamond, - apTeamMultisigOwners[0] + apTeamSigner ); const data = accountsUpdate.interface.encodeFunctionData("updateConfig", [ - newConfig.registrarContract || curConfig.registrarContract, + taskArgs.registrarContract || curConfig.registrarContract, ]); const apTeamMultiSig = APTeamMultiSig__factory.connect( curConfig.owner, // ensure connection to current owning APTeamMultiSig contract - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultiSig.submitTransaction(addresses.accounts.diamond, 0, data, "0x"); logger.out(`Tx hash: ${tx.hash}`); diff --git a/tasks/manage/accounts/updateOwner.ts b/tasks/manage/accounts/updateOwner.ts index 4457c4031..7ae894edc 100644 --- a/tasks/manage/accounts/updateOwner.ts +++ b/tasks/manage/accounts/updateOwner.ts @@ -1,18 +1,23 @@ import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import { APTeamMultiSig__factory, AccountsQueryEndowments__factory, AccountsUpdate__factory, } from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import {confirmAction, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {to: string; yes: boolean}; +type TaskArgs = {to: string; apTeamSignerPkey?: string; yes: boolean}; task("manage:AccountsDiamond:updateOwner", "Will update the owner of the Accounts Diamond") .addOptionalParam( "to", "Address of the new owner. Ensure at least one of `apTeamMultisigOwners` is the controller of this address. Will default to `contract-address.json > multiSig.apTeam.proxy` if none is provided." ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { @@ -20,12 +25,21 @@ task("manage:AccountsDiamond:updateOwner", "Will update the owner of the Account const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const newOwner = taskArgs.to || addresses.multiSig.apTeam.proxy; logger.out("Querying current Diamond owner..."); const accountsQueryEndowments = AccountsQueryEndowments__factory.connect( addresses.accounts.diamond, - apTeamMultisigOwners[0] + apTeamSigner ); const curOwner = (await accountsQueryEndowments.queryConfig()).owner; if (curOwner === newOwner) { @@ -42,12 +56,12 @@ task("manage:AccountsDiamond:updateOwner", "Will update the owner of the Account logger.out(`Transferring ownership to: ${newOwner}...`); const accountsUpdate = AccountsUpdate__factory.connect( addresses.accounts.diamond, - apTeamMultisigOwners[0] + apTeamSigner ); const data = accountsUpdate.interface.encodeFunctionData("updateOwner", [newOwner]); const apTeamMultiSig = APTeamMultiSig__factory.connect( curOwner, // ensure connection to current owning APTeamMultiSig contract - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultiSig.submitTransaction(addresses.accounts.diamond, 0, data, "0x"); logger.out(`Tx hash: ${tx.hash}`); diff --git a/tasks/manage/changeAdmin.ts b/tasks/manage/changeAdmin.ts index 2d30f00b0..708f34f7c 100644 --- a/tasks/manage/changeAdmin.ts +++ b/tasks/manage/changeAdmin.ts @@ -1,60 +1,112 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {BytesLike} from "ethers"; import {task} from "hardhat/config"; import {HardhatRuntimeEnvironment} from "hardhat/types"; -import {ITransparentUpgradeableProxy__factory, OwnershipFacet__factory} from "typechain-types"; -import {AddressObj, confirmAction, getAddresses, logger} from "utils"; +import { + IMultiSigGeneric__factory, + ITransparentUpgradeableProxy__factory, + OwnershipFacet__factory, + ProxyContract__factory, +} from "typechain-types"; +import { + AddressObj, + confirmAction, + connectSignerFromPkey, + getAddresses, + getEvents, + getSigners, + logger, +} from "utils"; -type TaskArgs = {current: string; new: string; yes: boolean}; +type TaskArgs = { + proxyAdminPkey: string; + newProxyAdmin: string; + yes: boolean; +}; -task("manage:changeAdmin", "Will update the admin for all proxy contracts") - .addParam("current", "Current admin address.") +task("manage:changeProxyAdmin", "Will update the proxy admin for all proxy contracts") + .addOptionalParam( + "proxyAdminPkey", + "The pkey for one of the current ProxyAdminMultiSig's owners." + ) .addParam( - "new", + "newProxyAdmin", "New admin address. Make sure to use an address of an account listed in the hardhat configuration for the target network." ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { const isConfirmed = - taskArgs.yes || (await confirmAction(`Change all contracts' admin to: ${taskArgs.new}`)); + taskArgs.yes || + (await confirmAction(`Change all contracts' admin to: ${taskArgs.newProxyAdmin}`)); if (!isConfirmed) { return logger.out("Confirmation denied.", logger.Level.Warn); } - const currentAdmin = await hre.ethers.getSigner(taskArgs.current); + let {proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } + + if (proxyAdminSigner.address === taskArgs.newProxyAdmin) { + return logger.out(`"${taskArgs.newProxyAdmin}" is already the proxy admin.`); + } const addresses = await getAddresses(hre); - await transferAccountOwnership(currentAdmin, taskArgs.new, addresses, hre); + await transferAccountOwnership(proxyAdminSigner, taskArgs.newProxyAdmin, addresses, hre); - await changeProxiesAdmin(currentAdmin, taskArgs.new, addresses, hre); + await changeProxiesAdmin(proxyAdminSigner, taskArgs.newProxyAdmin, addresses, hre); + + await hre.run("manage:registrar:updateConfig", { + proxyAdmin: taskArgs.newProxyAdmin, //address + yes: true, + }); } catch (error) { logger.out(error, logger.Level.Error); } }); async function transferAccountOwnership( - currentAdmin: SignerWithAddress, - newAdmin: string, + proxyAdminSigner: SignerWithAddress, + newProxyAdmin: string, addresses: AddressObj, hre: HardhatRuntimeEnvironment ) { try { + logger.out("Transferring Account diamond ownership..."); + const ownershipFacet = OwnershipFacet__factory.connect( addresses.accounts.diamond, - currentAdmin + hre.ethers.provider + ); + const data = ownershipFacet.interface.encodeFunctionData("transferOwnership", [newProxyAdmin]); + + const isExecuted = await submitMultiSigTx( + addresses.multiSig.proxyAdmin, + proxyAdminSigner, + ownershipFacet.address, + data ); - const tx = await ownershipFacet.transferOwnership(newAdmin); - await hre.ethers.provider.waitForTransaction(tx.hash); - logger.out("Transferred Account diamond ownership."); + + if (isExecuted) { + const newOwner = await ownershipFacet.owner(); + logger.out(`Owner is now set to: ${newOwner}`); + } } catch (error) { logger.out(`Failed to change admin for Account diamond, reason: ${error}`, logger.Level.Error); } } +/** + * Edge case: changing proxy admin address for all contracts that implement `fallback` function + * will never revert, but will nevertheless NOT update the admin. + */ async function changeProxiesAdmin( - currentAdmin: SignerWithAddress, - taskArguments: any, + proxyAdminSigner: SignerWithAddress, + newProxyAdmin: string, addresses: AddressObj, hre: HardhatRuntimeEnvironment ) { @@ -64,14 +116,29 @@ async function changeProxiesAdmin( for (const proxy of proxies) { try { + logger.divider(); logger.out(`Changing admin for ${proxy.name}...`); - const upgradeableProxy = ITransparentUpgradeableProxy__factory.connect( + + const proxyContract = ProxyContract__factory.connect(proxy.address, hre.ethers.provider); + const curAdmin = await proxyContract.getAdmin(); + logger.out(`Current Admin: ${curAdmin}`); + + const data = ITransparentUpgradeableProxy__factory.createInterface().encodeFunctionData( + "changeAdmin", + [newProxyAdmin] + ); + const isExecuted = await submitMultiSigTx( + addresses.multiSig.proxyAdmin, + proxyAdminSigner, proxy.address, - currentAdmin + data ); - const tx = await upgradeableProxy.changeAdmin(taskArguments.newAdmin); - logger.out(`Tx hash: ${tx.hash}`); - await tx.wait(); + + if (isExecuted) { + const proxyContract = ProxyContract__factory.connect(proxy.address, hre.ethers.provider); + const newAdmin = await proxyContract.getAdmin(); + logger.out(`New admin: ${newAdmin}`); + } } catch (error) { logger.out(`Failed to change admin, reason: ${error}`, logger.Level.Error); } @@ -79,21 +146,69 @@ async function changeProxiesAdmin( } function extractProxyContractAddresses(key: string, value: any): {name: string; address: string}[] { - if (!value) { + if (!value || typeof value !== "object") { return []; } - if (typeof value === "string") { - if (key.includes("Proxy")) { - return [{name: key, address: value}]; - } else { - return []; - } + if ("proxy" in value && !!value.proxy) { + return [{name: key, address: value.proxy}]; } - if (typeof value !== "object") { - return []; + return Object.entries(value).flatMap(([key, val]) => extractProxyContractAddresses(key, val)); +} + +async function submitMultiSigTx( + msAddress: string, + proxyAdminSigner: SignerWithAddress, + destination: string, + data: BytesLike +): Promise { + logger.out(`Submitting transaction to Multisig at address: ${msAddress}...`); + const multisig = IMultiSigGeneric__factory.connect(msAddress, proxyAdminSigner); + const tx = await multisig.submitTransaction(destination, 0, data, "0x"); + logger.out(`Tx hash: ${tx.hash}`); + const receipt = await tx.wait(); + + const transactionExecutedEvent = getEvents( + receipt.events, + multisig, + multisig.filters.TransactionExecuted() + ).at(0); + if (transactionExecutedEvent) { + return true; } - return Object.entries(value).flatMap(([key, val]) => extractProxyContractAddresses(key, val)); + const transactionSubmittedEvent = getEvents( + receipt.events, + multisig, + multisig.filters.TransactionSubmitted() + ).at(0); + if (!transactionSubmittedEvent) { + throw new Error("Unexpected: TransactionSubmitted not emitted."); + } + + const txId = transactionSubmittedEvent.args.transactionId; + + const isConfirmed = await multisig.isConfirmed(txId); + if (!isConfirmed) { + logger.out(`Transaction with ID "${txId}" submitted, awaiting confirmation by other owners.`); + return false; + } + + // is confirmed but not executed -> requires manual execution + logger.out(`Executing the new charity endowment with transaction ID: ${txId}...`); + const tx2 = await multisig.executeTransaction(txId); + logger.out(`Tx hash: ${tx2.hash}`); + const execReceipt = await tx2.wait(); + + const txExecuted = getEvents( + execReceipt.events, + multisig, + multisig.filters.TransactionExecuted() + ).at(0); + if (!txExecuted) { + throw new Error("Unexpected: TransactionExecuted not emitted."); + } + + return true; } diff --git a/tasks/manage/charityApplications/updateConfig.ts b/tasks/manage/charityApplications/updateConfig.ts index 42237b9fd..abfb96290 100644 --- a/tasks/manage/charityApplications/updateConfig.ts +++ b/tasks/manage/charityApplications/updateConfig.ts @@ -1,6 +1,14 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {CharityApplications__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger, structToObject} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + logger, + structToObject, +} from "utils"; type TaskArgs = { accountsDiamond?: string; @@ -9,6 +17,7 @@ type TaskArgs = { seedAsset?: string; seedSplitToLiquid?: number; seedAmount?: number; + appsSignerPkey?: string; yes: boolean; }; @@ -27,6 +36,10 @@ task("manage:CharityApplications:updateConfig", "Will update CharityApplications undefined, types.int ) + .addOptionalParam( + "appsSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { @@ -34,10 +47,20 @@ task("manage:CharityApplications:updateConfig", "Will update CharityApplications const addresses = await getAddresses(hre); const {charityApplicationsOwners} = await getSigners(hre); + let appsSigner: SignerWithAddress; + if (!charityApplicationsOwners && taskArgs.appsSignerPkey) { + appsSigner = await connectSignerFromPkey(taskArgs.appsSignerPkey, hre); + } else if (!charityApplicationsOwners) { + throw new Error( + "Must provide a pkey for Charity Applications Multisig signer on this network" + ); + } else { + appsSigner = charityApplicationsOwners[0]; + } const charityApplications = CharityApplications__factory.connect( addresses.multiSig.charityApplications.proxy, - charityApplicationsOwners[0] + appsSigner ); // fetch current config diff --git a/tasks/manage/createEndowment.ts b/tasks/manage/createEndowment.ts index 0bac8b139..77c7fce4e 100644 --- a/tasks/manage/createEndowment.ts +++ b/tasks/manage/createEndowment.ts @@ -1,4 +1,3 @@ -import {BigNumber} from "ethers"; import {task, types} from "hardhat/config"; import { AccountsCreateEndowment__factory, @@ -6,7 +5,7 @@ import { CharityApplications__factory, } from "typechain-types"; import {AccountMessages} from "typechain-types/contracts/multisigs/CharityApplications"; -import {getAddresses, getSigners, logger, structToObject} from "utils"; +import {getAddresses, getEvents, getSigners, logger, structToObject} from "utils"; type TaskArgs = {endowType: 0 | 1}; @@ -14,13 +13,13 @@ task("manage:createEndowment", "Will create a new endowment") .addParam("endowType", "0 - charity, 1 - ast, 2 - daf ", 0, types.int) .setAction(async (taskArgs: TaskArgs, hre) => { try { - const {apTeam1} = await getSigners(hre); + const {apTeam2} = await getSigners(hre); const addresses = await getAddresses(hre); const queryEndowmentFacet = AccountsQueryEndowments__factory.connect( addresses.accounts.diamond, - apTeam1 + apTeam2 ); const config = await queryEndowmentFacet.queryConfig(); @@ -33,7 +32,7 @@ task("manage:createEndowment", "Will create a new endowment") const defaultSettingsPermissionsStruct = { locked: false, delegate: { - addr: apTeam1.address, + addr: apTeam2.address, expires: 0, }, }; @@ -54,7 +53,7 @@ task("manage:createEndowment", "Will create a new endowment") endowType: taskArgs.endowType, // Charity logo: "", image: "", - members: [apTeam1.address], + members: [apTeam2.address], threshold: 1, allowlistedBeneficiaries: [], allowlistedContributors: [], @@ -96,29 +95,32 @@ task("manage:createEndowment", "Will create a new endowment") logger.out("Creating a charity applications proposal..."); const charityApplications = CharityApplications__factory.connect( addresses.multiSig.charityApplications.proxy, - apTeam1 + apTeam2 ); const tx = await charityApplications.proposeApplication(createEndowmentRequest, "0x"); logger.out(`Tx hash: ${tx.hash}`); const receipt = await tx.wait(); - if (!receipt.events?.length) { - throw new Error("Unexpected behaviour: no events emitted."); + const applicationProposedEvent = getEvents( + receipt.events, + charityApplications, + charityApplications.filters.ApplicationProposed() + ).at(0); + if (!applicationProposedEvent) { + throw new Error("Unexpected: ApplicationProposed not emitted."); } - const charityProposedEvent = receipt.events[0]; - if (!charityProposedEvent.args?.length) { - throw new Error("Unexpected behaviour: no args in ApplicationProposed event."); - } - if (!charityProposedEvent.args.at(0)) { - throw new Error("Unexpected behaviour: no proposalId in ApplicationProposed args."); - } - - const proposalId = charityProposedEvent.args.at(0); - logger.out(`Created proposal: ${proposalId}`); + const proposalId = applicationProposedEvent.args.proposalId; - const requireExecution = await charityApplications.requireExecution(); - if (requireExecution) { + const isExecuted = (await charityApplications.proposals(proposalId)).executed; + if (!isExecuted) { + const isConfirmed = await charityApplications.isProposalConfirmed(proposalId); + if (isConfirmed) { + logger.out( + `Proposal with ID "${proposalId}" submitted, awaiting confirmation by other owners.` + ); + return; + } logger.out(`Executing the new charity endowment with proposal ID: ${proposalId}...`); const tx2 = await charityApplications.executeProposal(proposalId); logger.out(`Tx hash: ${tx2.hash}`); @@ -127,7 +129,7 @@ task("manage:createEndowment", "Will create a new endowment") } else { const createEndowFacet = AccountsCreateEndowment__factory.connect( addresses.accounts.diamond, - apTeam1 + apTeam2 ); let tx = await createEndowFacet.createEndowment(createEndowmentRequest); logger.out(`Creating endowment...\nTx hash: ${tx.hash}`); @@ -138,7 +140,7 @@ task("manage:createEndowment", "Will create a new endowment") config.nextAccountId ); logger.out(`Added endowment with ID: ${config.nextAccountId.toNumber()}`); - logger.out(structToObject(newEndowmentDetails)); + logger.out(JSON.stringify(structToObject(newEndowmentDetails), undefined, 2)); logger.out(); } catch (error) { logger.out(error, logger.Level.Error); diff --git a/tasks/manage/gasFwdFactory/updateRegistrar.ts b/tasks/manage/gasFwdFactory/updateRegistrar.ts index 45bc0444f..f432e7c8d 100644 --- a/tasks/manage/gasFwdFactory/updateRegistrar.ts +++ b/tasks/manage/gasFwdFactory/updateRegistrar.ts @@ -1,8 +1,9 @@ import {task} from "hardhat/config"; -import {GasFwdFactory__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {APTeamMultiSig__factory, GasFwdFactory__factory} from "typechain-types"; +import {confirmAction, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {newRegistrar: string; yes: boolean}; +type TaskArgs = {newRegistrar: string; apTeamSignerPkey?: string; yes: boolean}; task( "manage:GasFwdFactory:updateRegistrar", @@ -12,17 +13,31 @@ task( "newRegistrar", "Address of the new registrar. Will default to `contract-address.json > registrar.proxy` if none is provided." ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { logger.divider(); const addresses = await getAddresses(hre); - const {proxyAdmin} = await getSigners(hre); + + const {apTeamMultisigOwners} = await getSigners(hre); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } const newRegistrar = taskArgs.newRegistrar || addresses.registrar.proxy; logger.out("Querying current GasFwdFactory registrar..."); - const gasFwdFactory = GasFwdFactory__factory.connect(addresses.gasFwd.factory, proxyAdmin); + const gasFwdFactory = GasFwdFactory__factory.connect(addresses.gasFwd.factory, apTeamSigner); const curRegistrar = await gasFwdFactory.registrar(); if (curRegistrar === newRegistrar) { return logger.out(`"${newRegistrar}" is already set as the registrar address.`); @@ -36,7 +51,12 @@ task( } logger.out(`Updating Registrar address to: ${newRegistrar}...`); - const tx = await gasFwdFactory.updateRegistrar(newRegistrar); + const apTeamMultiSig = APTeamMultiSig__factory.connect( + addresses.multiSig.apTeam.proxy, // ensure connection to current owning APTeamMultiSig contract + apTeamSigner + ); + const payload = gasFwdFactory.interface.encodeFunctionData("updateRegistrar", [newRegistrar]); + const tx = await apTeamMultiSig.submitTransaction(gasFwdFactory.address, 0, payload, "0x"); logger.out(`Tx hash: ${tx.hash}`); await tx.wait(); diff --git a/tasks/manage/indexFund/transferOwnership.ts b/tasks/manage/indexFund/transferOwnership.ts index a7328a49e..8e5bc0d59 100644 --- a/tasks/manage/indexFund/transferOwnership.ts +++ b/tasks/manage/indexFund/transferOwnership.ts @@ -1,8 +1,9 @@ import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, IndexFund__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import {confirmAction, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {to: string; yes: boolean}; +type TaskArgs = {to: string; apTeamSignerPkey?: string; yes: boolean}; task("manage:IndexFund:transferOwnership", "Will update the owner of the IndexFund") .addOptionalParam( @@ -16,13 +17,19 @@ task("manage:IndexFund:transferOwnership", "Will update the owner of the IndexFu const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const newOwner = taskArgs.to || addresses.multiSig.apTeam.proxy; logger.out("Querying current IndexFund owner..."); - const indexFund = IndexFund__factory.connect( - addresses.indexFund.proxy, - apTeamMultisigOwners[0] - ); + const indexFund = IndexFund__factory.connect(addresses.indexFund.proxy, apTeamSigner); const curOwner = await indexFund.owner(); if (curOwner === newOwner) { return logger.out(`"${newOwner}" is already the owner.`); @@ -39,7 +46,7 @@ task("manage:IndexFund:transferOwnership", "Will update the owner of the IndexFu const data = indexFund.interface.encodeFunctionData("transferOwnership", [newOwner]); const apTeamMultiSig = APTeamMultiSig__factory.connect( curOwner, // ensure connection to current owning APTeamMultiSig contract - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultiSig.submitTransaction(indexFund.address, 0, data, "0x"); logger.out(`Tx hash: ${tx.hash}`); diff --git a/tasks/manage/indexFund/updateConfig.ts b/tasks/manage/indexFund/updateConfig.ts index 80aa62fe5..6d53f383f 100644 --- a/tasks/manage/indexFund/updateConfig.ts +++ b/tasks/manage/indexFund/updateConfig.ts @@ -1,11 +1,20 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, IndexFund__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger, structToObject} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + logger, + structToObject, +} from "utils"; type TaskArgs = { registrarContract: string; fundingGoal: number; fundRotation: number; + apTeamSignerPkey?: string; yes: boolean; }; @@ -16,6 +25,10 @@ task("manage:IndexFund:updateConfig", "Will update the config of the IndexFund") ) .addOptionalParam("fundingGoal", "Funding rotation blocks.", undefined, types.int) .addOptionalParam("fundRotation", "Funding goal amount.", undefined, types.int) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { @@ -25,11 +38,17 @@ task("manage:IndexFund:updateConfig", "Will update the config of the IndexFund") const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + logger.out("Querying current IndexFund registrar..."); - const indexFund = IndexFund__factory.connect( - addresses.indexFund.proxy, - apTeamMultisigOwners[0] - ); + const indexFund = IndexFund__factory.connect(addresses.indexFund.proxy, apTeamSigner); const struct = await indexFund.queryConfig(); const curConfig = structToObject(struct); logger.out(curConfig); @@ -47,7 +66,7 @@ task("manage:IndexFund:updateConfig", "Will update the config of the IndexFund") logger.out("Updating config..."); const apTeamMultiSig = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, // ensure connection to current owning APTeamMultiSig contract - apTeamMultisigOwners[0] + apTeamSigner ); const data = indexFund.interface.encodeFunctionData("updateConfig", [ newConfig.registrarContract || curConfig.registrarContract, diff --git a/tasks/manage/registrar/setAccountsChainAndAddress.ts b/tasks/manage/registrar/setAccountsChainAndAddress.ts index f3d66bc0f..b093cd35b 100644 --- a/tasks/manage/registrar/setAccountsChainAndAddress.ts +++ b/tasks/manage/registrar/setAccountsChainAndAddress.ts @@ -1,19 +1,35 @@ import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {accountsDiamond: string; chainName: string}; +type TaskArgs = {accountsDiamond: string; chainName: string; apTeamSignerPkey?: string}; task("manage:registrar:setAccountsChainAndAddress") .addParam("accountsDiamond", "Address of the accounts contract on target Axelar blockchain") .addParam("chainName", "The Axelar blockchain name of the accounts contract") + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -25,7 +41,7 @@ task("manage:registrar:setAccountsChainAndAddress") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setFeeSetting.ts b/tasks/manage/registrar/setFeeSetting.ts index 0a526541e..d81c861d9 100644 --- a/tasks/manage/registrar/setFeeSetting.ts +++ b/tasks/manage/registrar/setFeeSetting.ts @@ -1,8 +1,16 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, Registrar__factory} from "typechain-types"; -import {FeeTypes, getAddresses, getEnumKeys, getSigners, logger} from "utils"; +import { + FeeTypes, + connectSignerFromPkey, + getAddresses, + getEnumKeys, + getSigners, + logger, +} from "utils"; -type TaskArgs = {feeType: number; payoutAddress: string; bps: number}; +type TaskArgs = {feeType: number; payoutAddress: string; bps: number; apTeamSignerPkey?: string}; task("manage:registrar:setFeeSettings") .addParam( @@ -14,14 +22,29 @@ task("manage:registrar:setFeeSettings") types.int ) .addParam("payoutAddress", "Address of fee recipient", "", types.string) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addParam("bps", "basis points to be applied for this fee", 0, types.int) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -44,7 +67,7 @@ task("manage:registrar:setFeeSettings") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setGasByToken.ts b/tasks/manage/registrar/setGasByToken.ts index aa030a259..ebbb7caef 100644 --- a/tasks/manage/registrar/setGasByToken.ts +++ b/tasks/manage/registrar/setGasByToken.ts @@ -1,9 +1,10 @@ import {BigNumber} from "ethers"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {task, types} from "hardhat/config"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {gas: number; tokenAddress: string}; +type TaskArgs = {gas: number; tokenAddress: string; apTeamSignerPkey?: string}; task("manage:registrar:setGasByToken") .addParam("tokenAddress", "Address of the token", "", types.string) @@ -13,13 +14,28 @@ task("manage:registrar:setGasByToken") 0, types.int ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -39,7 +55,7 @@ task("manage:registrar:setGasByToken") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setNetworkInfo.ts b/tasks/manage/registrar/setNetworkInfo.ts index 7139e179f..74fca3297 100644 --- a/tasks/manage/registrar/setNetworkInfo.ts +++ b/tasks/manage/registrar/setNetworkInfo.ts @@ -1,17 +1,21 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {updateRegistrarNetworkConnections} from "tasks/helpers"; import {LocalRegistrarLib} from "typechain-types/contracts/core/registrar/LocalRegistrar"; import { + connectSignerFromPkey, getAddresses, logger, getAddressesByNetworkId, getChainIdFromNetworkName, DEFAULT_CONTRACT_ADDRESS_FILE_PATH, + getSigners, } from "utils"; type TaskArgs = { networkName: string; refundAddr?: string; + apTeamSignerPkey?: string; }; task("manage:registrar:setNetworkInfo", "Set network info for a specified network") @@ -27,12 +31,27 @@ task("manage:registrar:setNetworkInfo", "Set network info for a specified networ "", types.string ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const networkId = getChainIdFromNetworkName(taskArguments.networkName); const thisNetworkAddresses = await getAddresses(hre); + + const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const thatNetworkAddresses = getAddressesByNetworkId( networkId, DEFAULT_CONTRACT_ADDRESS_FILE_PATH @@ -51,6 +70,7 @@ task("manage:registrar:setNetworkInfo", "Set network info for a specified networ thisNetworkAddresses.registrar.proxy, thisNetworkAddresses.multiSig.apTeam.proxy, newNetworkInfo, + apTeamSigner, hre ); }); diff --git a/tasks/manage/registrar/setRebalParams.ts b/tasks/manage/registrar/setRebalParams.ts index 44baeb8f9..8da88159d 100644 --- a/tasks/manage/registrar/setRebalParams.ts +++ b/tasks/manage/registrar/setRebalParams.ts @@ -1,6 +1,7 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; const NULL_NUMBER = 0; const NULL_STRING = ""; @@ -13,6 +14,7 @@ type TaskArgs = { lockedRebalanceToLiquid: number; principleDistribution: number; rebalanceLiquidProfits: boolean; + apTeamSignerPkey?: string; }; task("manage:registrar:setRebalParams") @@ -42,13 +44,28 @@ task("manage:registrar:setRebalParams") types.int ) .addOptionalParam("basis", "The precision of rebalance rates", NULL_NUMBER, types.int) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -107,7 +124,7 @@ task("manage:registrar:setRebalParams") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setStratApproval.ts b/tasks/manage/registrar/setStratApproval.ts index 948693287..3de28fef8 100644 --- a/tasks/manage/registrar/setStratApproval.ts +++ b/tasks/manage/registrar/setStratApproval.ts @@ -1,6 +1,8 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; import { + connectSignerFromPkey, getAddresses, getSigners, StratConfig, @@ -10,7 +12,7 @@ import { } from "utils"; import {allStrategyConfigs} from "../../../contracts/integrations/stratConfig"; -type TaskArgs = {name: string; approvalState: number}; +type TaskArgs = {name: string; approvalState: number; apTeamSignerPkey?: string}; task("manage:registrar:setStratApproval") .addParam( @@ -31,13 +33,27 @@ task("manage:registrar:setStratApproval") 0, types.int ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; + const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -58,7 +74,7 @@ task("manage:registrar:setStratApproval") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setStratParams.ts b/tasks/manage/registrar/setStratParams.ts index 6f0c7ca83..3e627ca05 100644 --- a/tasks/manage/registrar/setStratParams.ts +++ b/tasks/manage/registrar/setStratParams.ts @@ -1,11 +1,13 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {StratConfig, getAddresses, getSigners, logger} from "utils"; +import {StratConfig, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; import {allStrategyConfigs} from "../../../contracts/integrations/stratConfig"; type TaskArgs = { name: string; modifyExisting: boolean; + apTeamSignerPkey?: string; }; task("manage:registrar:setStratParams") @@ -23,15 +25,26 @@ task("manage:registrar:setStratParams") false, types.boolean ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect( - addresses.registrar.proxy, - apTeamMultisigOwners[0] - ); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(addresses.registrar.proxy, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -69,7 +82,7 @@ task("manage:registrar:setStratParams") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setTokenAccepted.ts b/tasks/manage/registrar/setTokenAccepted.ts index d2098673c..0e5ff86cd 100644 --- a/tasks/manage/registrar/setTokenAccepted.ts +++ b/tasks/manage/registrar/setTokenAccepted.ts @@ -1,19 +1,34 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {acceptanceState: boolean; tokenAddress: string}; +type TaskArgs = {acceptanceState: boolean; tokenAddress: string; apTeamSignerPkey?: string}; task("manage:registrar:setTokenAccepted") .addParam("tokenAddress", "Address of the token", "", types.string) .addParam("acceptanceState", "Boolean for acceptance state", false, types.boolean) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -33,7 +48,7 @@ task("manage:registrar:setTokenAccepted") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setVaultEmitterAddress.ts b/tasks/manage/registrar/setVaultEmitterAddress.ts index e87d8b74a..afa1b0963 100644 --- a/tasks/manage/registrar/setVaultEmitterAddress.ts +++ b/tasks/manage/registrar/setVaultEmitterAddress.ts @@ -1,11 +1,16 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import {confirmAction, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {vaultEmitter: string; yes: boolean}; +type TaskArgs = {vaultEmitter: string; apTeamSignerPkey?: string; yes: boolean}; task("manage:registrar:setVaultEmitterAddress") .addParam("vaultEmitter", "Address of the VaultEmitter contract", undefined, types.string) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { @@ -14,10 +19,16 @@ task("manage:registrar:setVaultEmitterAddress") const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect( - addresses.registrar.proxy, - apTeamMultisigOwners[0] - ); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(addresses.registrar.proxy, apTeamSigner); const currVaultEmitter = await registrar.getVaultEmitterAddress(); if (currVaultEmitter === taskArgs.vaultEmitter) { return logger.out(`VaultEmitter address is already set to "${currVaultEmitter}".`); @@ -35,7 +46,7 @@ task("manage:registrar:setVaultEmitterAddress") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/setVaultOperatorStatus.ts b/tasks/manage/registrar/setVaultOperatorStatus.ts index 1d228fac0..61d2231fb 100644 --- a/tasks/manage/registrar/setVaultOperatorStatus.ts +++ b/tasks/manage/registrar/setVaultOperatorStatus.ts @@ -1,19 +1,34 @@ import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {Registrar__factory, APTeamMultiSig__factory} from "typechain-types"; -import {getAddresses, getSigners, logger} from "utils"; +import {connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {operator: string; status: boolean}; +type TaskArgs = {operator: string; status: boolean; apTeamSignerPkey?: string}; task("manage:registrar:setVaultOperatorStatus") .addParam("operator", "Address of the vault operator") .addParam("status", "The state to set the operator to") + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async function (taskArguments: TaskArgs, hre) { logger.divider(); logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const registrarAddress = addresses["registrar"]["proxy"]; const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect(registrarAddress, apTeamMultisigOwners[0]); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArguments.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArguments.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(registrarAddress, apTeamSigner); logger.pad(50, "Connected to Registrar at: ", registrar.address); logger.divider(); @@ -25,7 +40,7 @@ task("manage:registrar:setVaultOperatorStatus") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( registrar.address, diff --git a/tasks/manage/registrar/transferOwnership.ts b/tasks/manage/registrar/transferOwnership.ts index 1435dcbb8..91fbf1b04 100644 --- a/tasks/manage/registrar/transferOwnership.ts +++ b/tasks/manage/registrar/transferOwnership.ts @@ -1,14 +1,19 @@ import {task} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, Registrar__factory} from "typechain-types"; -import {confirmAction, getAddresses, getSigners, logger} from "utils"; +import {confirmAction, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; -type TaskArgs = {to: string; yes: boolean}; +type TaskArgs = {to: string; apTeamSignerPkey?: string; yes: boolean}; task("manage:registrar:transferOwnership") .addOptionalParam( "to", "Address of the new owner. Ensure at least one of `apTeamMultisigOwners` is the controller of this address. Will default to `contract-address.json > multiSig.apTeam.proxy` if none is provided." ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { try { @@ -16,10 +21,17 @@ task("manage:registrar:transferOwnership") logger.out("Connecting to registrar on specified network..."); const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); - const registrar = Registrar__factory.connect( - addresses.registrar.proxy, - apTeamMultisigOwners[0] - ); + + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + + const registrar = Registrar__factory.connect(addresses.registrar.proxy, apTeamSigner); logger.out(`Connected to Registrar at: ${registrar.address}`); const newOwner = taskArgs.to || addresses.multiSig.apTeam.proxy; @@ -40,7 +52,7 @@ task("manage:registrar:transferOwnership") const data = registrar.interface.encodeFunctionData("transferOwnership", [newOwner]); const apTeamMultiSig = APTeamMultiSig__factory.connect( curOwner, // ensure connection to current owning APTeamMultiSig contract - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultiSig.submitTransaction(registrar.address, 0, data, "0x"); logger.out(`Tx hash: ${tx.hash}`); diff --git a/tasks/manage/registrar/updateConfig.ts b/tasks/manage/registrar/updateConfig.ts index 985695223..713a7950e 100644 --- a/tasks/manage/registrar/updateConfig.ts +++ b/tasks/manage/registrar/updateConfig.ts @@ -1,9 +1,18 @@ import {task, types} from "hardhat/config"; +import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; import {APTeamMultiSig__factory, Registrar__factory} from "typechain-types"; import {RegistrarMessages} from "typechain-types/contracts/core/registrar/Registrar"; -import {confirmAction, getAddresses, getSigners, logger, structToObject} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + logger, + structToObject, +} from "utils"; type TaskArgs = Partial & { + apTeamSignerPkey?: string; yes: boolean; }; @@ -99,6 +108,10 @@ task("manage:registrar:updateConfig", "Will update Accounts Diamond config") undefined, types.string ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .addFlag("yes", "Automatic yes to prompt.") .setAction(async (taskArgs: TaskArgs, hre) => { logger.divider(); @@ -108,6 +121,15 @@ task("manage:registrar:updateConfig", "Will update Accounts Diamond config") const addresses = await getAddresses(hre); const {apTeamMultisigOwners} = await getSigners(hre); + let apTeamSigner: SignerWithAddress; + if (!apTeamMultisigOwners && taskArgs.apTeamSignerPkey) { + apTeamSigner = await connectSignerFromPkey(taskArgs.apTeamSignerPkey, hre); + } else if (!apTeamMultisigOwners) { + throw new Error("Must provide a pkey for AP Team signer on this network"); + } else { + apTeamSigner = apTeamMultisigOwners[0]; + } + const {yes, ...dirtyConfigValues} = taskArgs; const updateConfigRequest = assignDefinedValues(dirtyConfigValues); @@ -124,10 +146,7 @@ task("manage:registrar:updateConfig", "Will update Accounts Diamond config") return logger.out("Confirmation denied.", logger.Level.Warn); } - const registrarContract = Registrar__factory.connect( - addresses.registrar.proxy, - apTeamMultisigOwners[0] - ); + const registrarContract = Registrar__factory.connect(addresses.registrar.proxy, apTeamSigner); logger.out("Fetching current Registrar's config..."); const struct = await registrarContract.queryConfig(); @@ -142,7 +161,7 @@ task("manage:registrar:updateConfig", "Will update Accounts Diamond config") ]); const apTeamMultisigContract = APTeamMultiSig__factory.connect( addresses.multiSig.apTeam.proxy, - apTeamMultisigOwners[0] + apTeamSigner ); const tx = await apTeamMultisigContract.submitTransaction( addresses.registrar.proxy, diff --git a/tasks/manage/updateRegistrar.ts b/tasks/manage/updateRegistrar.ts index edf75e0db..9737bcf84 100644 --- a/tasks/manage/updateRegistrar.ts +++ b/tasks/manage/updateRegistrar.ts @@ -1,11 +1,13 @@ import {task} from "hardhat/config"; +import config from "config"; import {cliTypes} from "tasks/types"; import {RegistrarMessages} from "typechain-types/contracts/core/registrar/interfaces/IRegistrar"; -import {ADDRESS_ZERO, getAddresses, getSigners, logger} from "utils"; +import {ADDRESS_ZERO, connectSignerFromPkey, getAddresses, getSigners, logger} from "utils"; type TaskArgs = { acceptedTokens: string[]; acceptanceStates: boolean[]; + apTeamSignerPkey?: string; }; task( @@ -19,16 +21,21 @@ task( [], cliTypes.array.boolean ) + .addOptionalParam( + "apTeamSignerPkey", + "If running on prod, provide a pkey for a valid APTeam Multisig Owner." + ) .setAction(async (taskArgs: TaskArgs, hre) => { try { - const {proxyAdmin, treasury} = await getSigners(hre); + const {treasury} = await getSigners(hre); + let treasuryAddress = treasury ? treasury.address : config.PROD_CONFIG.Treasury; const addresses = await getAddresses(hre); let newConfig: RegistrarMessages.UpdateConfigRequestStruct = { accountsContract: addresses.accounts.diamond, apTeamMultisig: addresses.multiSig.apTeam.proxy, - treasury: treasury.address, + treasury: treasuryAddress, indexFundContract: addresses.indexFund.proxy, haloToken: ADDRESS_ZERO, govContract: ADDRESS_ZERO, @@ -38,20 +45,33 @@ task( multisigFactory: addresses.multiSig.endowment.factory, multisigEmitter: addresses.multiSig.endowment.emitter.proxy, charityApplications: addresses.multiSig.charityApplications.proxy, - proxyAdmin: proxyAdmin.address, + proxyAdmin: addresses.multiSig.proxyAdmin, usdcAddress: addresses.tokens.usdc, wMaticAddress: addresses.tokens.wmatic, gasFwdFactory: addresses.gasFwd.factory, }; - await hre.run("manage:registrar:updateConfig", { - ...newConfig, - yes: true, - }); - await hre.run("manage:registrar:setVaultEmitterAddress", { - vaultEmitter: addresses.vaultEmitter.proxy, - yes: true, - }); + if (taskArgs.apTeamSignerPkey) { + await hre.run("manage:registrar:updateConfig", { + ...newConfig, + apTeamSignerPkey: taskArgs.apTeamSignerPkey, + yes: true, + }); + await hre.run("manage:registrar:setVaultEmitterAddress", { + vaultEmitter: addresses.vaultEmitter.proxy, + apTeamSignerPkey: taskArgs.apTeamSignerPkey, + yes: true, + }); + } else { + await hre.run("manage:registrar:updateConfig", { + ...newConfig, + yes: true, + }); + await hre.run("manage:registrar:setVaultEmitterAddress", { + vaultEmitter: addresses.vaultEmitter.proxy, + yes: true, + }); + } if (taskArgs.acceptedTokens.length > 0) { logger.divider(); @@ -60,7 +80,16 @@ task( try { const tokenAddress = taskArgs.acceptedTokens[i]; const acceptanceState = taskArgs.acceptanceStates.at(i) ?? true; - await hre.run("manage:registrar:setTokenAccepted", {tokenAddress, acceptanceState}); + const signerKey = taskArgs.apTeamSignerPkey; + if (taskArgs.apTeamSignerPkey) { + await hre.run("manage:registrar:setTokenAccepted", { + tokenAddress, + acceptanceState, + signerKey, + }); + } else { + await hre.run("manage:registrar:setTokenAccepted", {tokenAddress, acceptanceState}); + } } catch (error) { logger.out(error, logger.Level.Error); } diff --git a/tasks/manage/verifyRegistrar.ts b/tasks/manage/verifyRegistrar.ts index 22d335802..b78cb72f9 100644 --- a/tasks/manage/verifyRegistrar.ts +++ b/tasks/manage/verifyRegistrar.ts @@ -1,18 +1,10 @@ import {task} from "hardhat/config"; -import {Registrar__factory} from "typechain-types"; -import {getAddresses, getSigners, logger, verify} from "utils"; +import {getAddresses, logger, verify} from "utils"; task("manage:verifyRegistrar", "Will verify the Registrar implementation contract").setAction( async (_, hre) => { try { const addresses = await getAddresses(hre); - const {proxyAdmin} = await getSigners(hre); - - let registrar = Registrar__factory.connect(addresses.registrar.proxy, proxyAdmin); - - let registrarConfig = await registrar.queryConfig(); - logger.out(`Registrar owner: ${registrarConfig.proxyAdmin}`); - await verify(hre, {address: addresses.registrar.implementation, contractName: "Registrar"}); } catch (error) { logger.out(error, logger.Level.Error); diff --git a/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts b/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts index eb4911ec6..073ee9b1a 100644 --- a/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts +++ b/tasks/upgrade/endowmentMultiSig/upgradeEmitter.ts @@ -2,9 +2,11 @@ import {task} from "hardhat/config"; import { EndowmentMultiSigEmitter__factory, ITransparentUpgradeableProxy__factory, + ProxyAdminMultiSig__factory, } from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -18,6 +20,7 @@ type TaskArgs = { factory?: string; skipVerify: boolean; yes: boolean; + proxyAdminPkey?: string; }; task( @@ -26,6 +29,7 @@ task( ) .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") .setAction(async (taskArgs: TaskArgs, hre) => { try { logger.divider(); @@ -36,23 +40,33 @@ task( return logger.out("Confirmation denied.", logger.Level.Warn); } - const {proxyAdmin} = await getSigners(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } const addresses = await getAddresses(hre); logger.out("Deploying implementation..."); - const Emitter = new EndowmentMultiSigEmitter__factory(proxyAdmin); + const Emitter = new EndowmentMultiSigEmitter__factory(deployer); const emitter = await Emitter.deploy(); logger.out(`Tx hash: ${emitter.deployTransaction.hash}`); await emitter.deployed(); logger.out(`Address: ${emitter.address}`); logger.out("Upgrading proxy..."); - const proxy = ITransparentUpgradeableProxy__factory.connect( + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const emitterProxy = ITransparentUpgradeableProxy__factory.connect( addresses.multiSig.endowment.emitter.proxy, - proxyAdmin + deployer ); - const tx = await proxy.upgradeTo(emitter.address); + const payload = emitterProxy.interface.encodeFunctionData("upgradeTo", [emitter.address]); + const tx = await proxyAdminMultisig.submitTransaction(emitterProxy.address, 0, payload, "0x"); logger.out(`Tx hash: ${tx.hash}`); await tx.wait(); diff --git a/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts b/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts index 1f7794b43..70a825425 100644 --- a/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts +++ b/tasks/upgrade/endowmentMultiSig/upgradeImplementation.ts @@ -1,7 +1,12 @@ import {task} from "hardhat/config"; -import {EndowmentMultiSig__factory, EndowmentMultiSigFactory__factory} from "typechain-types"; +import { + EndowmentMultiSig__factory, + EndowmentMultiSigFactory__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -15,6 +20,7 @@ type TaskArgs = { factory?: string; skipVerify: boolean; yes: boolean; + proxyAdminPkey?: string; }; task( @@ -27,6 +33,7 @@ task( ) .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") .setAction(async (taskArgs: TaskArgs, hre) => { try { logger.divider(); @@ -38,7 +45,12 @@ task( return logger.out("Confirmation denied.", logger.Level.Warn); } - const {proxyAdmin} = await getSigners(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } const addresses = await getAddresses(hre); @@ -46,17 +58,30 @@ task( taskArgs.factory || addresses.multiSig.endowment.factory; logger.out("Deploying a new EndowmentMultiSig contract..."); - const factory = new EndowmentMultiSig__factory(proxyAdmin); + const factory = new EndowmentMultiSig__factory(deployer); const contract = await factory.deploy(); await contract.deployed(); logger.out(`Address: ${contract.address}`); logger.out("Upgrading EndowmentMultiSigFactory's implementation address..."); - const EndowmentMultiSigFactory = EndowmentMultiSigFactory__factory.connect( + const endowmentMultiSigFactory = EndowmentMultiSigFactory__factory.connect( + EndowmentMultiSigFactoryAddress, + proxyAdminSigner + ); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const payload = endowmentMultiSigFactory.interface.encodeFunctionData( + "updateImplementation", + [contract.address] + ); + const tx = await proxyAdminMultisig.submitTransaction( EndowmentMultiSigFactoryAddress, - proxyAdmin + 0, + payload, + "0x" ); - const tx = await EndowmentMultiSigFactory.updateImplementation(contract.address); logger.out(`Tx hash: ${tx.hash}`); await tx.wait(); diff --git a/tasks/upgrade/upgradeAPTeamMultiSig.ts b/tasks/upgrade/upgradeAPTeamMultiSig.ts index e54556660..c2611db6a 100644 --- a/tasks/upgrade/upgradeAPTeamMultiSig.ts +++ b/tasks/upgrade/upgradeAPTeamMultiSig.ts @@ -1,7 +1,12 @@ import {task} from "hardhat/config"; -import {APTeamMultiSig__factory, ITransparentUpgradeableProxy__factory} from "typechain-types"; +import { + APTeamMultiSig__factory, + ITransparentUpgradeableProxy__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -14,54 +19,74 @@ import { task("upgrade:APTeamMultiSig", "Will upgrade the APTeamMultiSig") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { - try { - logger.divider(); + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") + .setAction( + async (taskArgs: {skipVerify: boolean; yes: boolean; proxyAdminPkey?: string}, hre) => { + try { + logger.divider(); - const isConfirmed = taskArgs.yes || (await confirmAction("Upgrading APTeamMultiSig...")); - if (!isConfirmed) { - return logger.out("Confirmation denied.", logger.Level.Warn); - } + const isConfirmed = taskArgs.yes || (await confirmAction("Upgrading APTeamMultiSig...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } - const {proxyAdmin} = await getSigners(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } - const addresses = await getAddresses(hre); + const addresses = await getAddresses(hre); - // Update APTeamMultiSig - logger.out("Deploying APTeamMultiSig..."); - const apTeamFactory = new APTeamMultiSig__factory(proxyAdmin); - const apTeamMultiSig = await apTeamFactory.deploy(); - await apTeamMultiSig.deployed(); - logger.out(`Address: ${apTeamMultiSig.address}`); + // Update APTeamMultiSig + logger.out("Deploying APTeamMultiSig..."); + const apTeamFactory = new APTeamMultiSig__factory(deployer); + const apTeamMultiSig = await apTeamFactory.deploy(); + await apTeamMultiSig.deployed(); + logger.out(`Address: ${apTeamMultiSig.address}`); - logger.out("Upgrading APTeamMultiSig proxy implementation..."); - const apTeamProxy = ITransparentUpgradeableProxy__factory.connect( - addresses.multiSig.apTeam.proxy, - proxyAdmin - ); - const tx = await apTeamProxy.upgradeTo(apTeamMultiSig.address); - logger.out(`Tx hash: ${tx.hash}`); - await tx.wait(); + logger.out("Upgrading APTeamMultiSig proxy implementation..."); + const apTeamProxy = ITransparentUpgradeableProxy__factory.connect( + addresses.multiSig.apTeam.proxy, + deployer + ); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const payload = apTeamProxy.interface.encodeFunctionData("upgradeTo", [ + apTeamMultiSig.address, + ]); + const tx = await proxyAdminMultisig.submitTransaction( + apTeamProxy.address, + 0, + payload, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); - await updateAddresses( - { - multiSig: { - apTeam: { - implementation: apTeamMultiSig.address, + await updateAddresses( + { + multiSig: { + apTeam: { + implementation: apTeamMultiSig.address, + }, }, }, - }, - hre - ); + hre + ); - if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { - await verify(hre, { - address: apTeamMultiSig.address, - contract: "contracts/multisigs/APTeamMultiSig.sol:APTeamMultiSig", - contractName: getContractName(apTeamFactory), - }); + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, { + address: apTeamMultiSig.address, + contract: "contracts/multisigs/APTeamMultiSig.sol:APTeamMultiSig", + contractName: getContractName(apTeamFactory), + }); + } + } catch (error) { + logger.out(error, logger.Level.Error); } - } catch (error) { - logger.out(error, logger.Level.Error); } - }); + ); diff --git a/tasks/upgrade/upgradeCharityApplications.ts b/tasks/upgrade/upgradeCharityApplications.ts index 3de5d5302..92f133829 100644 --- a/tasks/upgrade/upgradeCharityApplications.ts +++ b/tasks/upgrade/upgradeCharityApplications.ts @@ -1,7 +1,12 @@ -import {task, types} from "hardhat/config"; -import {CharityApplications__factory, ITransparentUpgradeableProxy__factory} from "typechain-types"; +import {task} from "hardhat/config"; +import { + CharityApplications__factory, + ITransparentUpgradeableProxy__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -14,11 +19,13 @@ import { type TaskArgs = { skipVerify: boolean; yes: boolean; + proxyAdminPkey?: string; }; task("upgrade:CharityApplications", "Will upgrade the implementation of CharityApplications") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") .setAction(async (taskArgs: TaskArgs, hre) => { try { logger.divider(); @@ -30,25 +37,43 @@ task("upgrade:CharityApplications", "Will upgrade the implementation of CharityA return logger.out("Confirmation denied.", logger.Level.Warn); } - const {proxyAdmin} = await getSigners(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } + const addresses = await getAddresses(hre); // deploy implementation logger.out("Deploying CharityApplications..."); - const charityApplicationsFactory = new CharityApplications__factory(proxyAdmin); + const charityApplicationsFactory = new CharityApplications__factory(deployer); const charityApplications = await charityApplicationsFactory.deploy(); await charityApplications.deployed(); logger.out(`Address: ${charityApplications.address}`); // upgrade proxy logger.out("Upgrading proxy..."); - const apTeamProxy = ITransparentUpgradeableProxy__factory.connect( + const charityApplicationsProxy = ITransparentUpgradeableProxy__factory.connect( addresses.multiSig.charityApplications.proxy, - proxyAdmin + deployer + ); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const payload = charityApplicationsProxy.interface.encodeFunctionData("upgradeTo", [ + charityApplications.address, + ]); + const tx = await proxyAdminMultisig.submitTransaction( + charityApplicationsProxy.address, + 0, + payload, + "0x" ); - const tx1 = await apTeamProxy.upgradeTo(charityApplications.address); - logger.out(`Tx hash: ${tx1.hash}`); - await tx1.wait(); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); // update address & verify await updateAddresses( diff --git a/tasks/upgrade/upgradeContractsUsingAccountStorage.ts b/tasks/upgrade/upgradeContractsUsingAccountStorage.ts index 517fe29c3..747265298 100644 --- a/tasks/upgrade/upgradeContractsUsingAccountStorage.ts +++ b/tasks/upgrade/upgradeContractsUsingAccountStorage.ts @@ -1,13 +1,16 @@ import {task} from "hardhat/config"; import {confirmAction, logger} from "utils"; +type TaskArgs = {proxyAdminPkey?: string; skipVerify: boolean; yes: boolean}; + task( "upgrade:ContractsUsingAccountStorage", "Will redeploy all contracts that use AccountStorage struct" ) .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") + .setAction(async (taskArgs: TaskArgs, hre) => { try { const isConfirmed = taskArgs.yes || (await confirmAction("Upgrading all contracts using AccountStorage...")); @@ -15,9 +18,14 @@ task( return logger.out("Confirmation denied.", logger.Level.Warn); } - await hre.run("upgrade:CharityApplications", {skipVerify: taskArgs.skipVerify, yes: true}); + await hre.run("upgrade:CharityApplications", { + proxyAdminPkey: taskArgs.proxyAdminPkey, + skipVerify: taskArgs.skipVerify, + yes: true, + }); await hre.run("upgrade:facets", { facets: ["all"], + proxyAdminPkey: taskArgs.proxyAdminPkey, skipVerify: taskArgs.skipVerify, yes: true, }); diff --git a/tasks/upgrade/upgradeFacets/cutDiamond.ts b/tasks/upgrade/upgradeFacets/cutDiamond.ts index 37bdcddfc..d38243114 100644 --- a/tasks/upgrade/upgradeFacets/cutDiamond.ts +++ b/tasks/upgrade/upgradeFacets/cutDiamond.ts @@ -1,25 +1,29 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {HardhatRuntimeEnvironment} from "hardhat/types"; -import {DiamondCutFacet__factory, DiamondInit__factory} from "typechain-types"; +import { + DiamondCutFacet__factory, + DiamondInit__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import {logger} from "utils"; - import {FacetCut} from "./types"; export default async function cutDiamond( diamondAddress: string, - diamondOwner: SignerWithAddress, - facetCuts: FacetCut[], - hre: HardhatRuntimeEnvironment + proxyAdminMultiSig: string, + proxyAdmin: SignerWithAddress, + facetCuts: FacetCut[] ) { logger.out("Updating Diamond with new facet addresses..."); - - const diamondCut = DiamondCutFacet__factory.connect(diamondAddress, diamondOwner); - const diamondInit = DiamondInit__factory.connect(diamondAddress, diamondOwner); + const diamondCut = DiamondCutFacet__factory.connect(diamondAddress, proxyAdmin); + const diamondInit = DiamondInit__factory.connect(diamondAddress, proxyAdmin); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect(proxyAdminMultiSig, proxyAdmin); const cuts = facetCuts.map((x) => x.cut); - const tx = await diamondCut.diamondCut(cuts, diamondInit.address, "0x"); - const receipt = await hre.ethers.provider.waitForTransaction(tx.hash); - - if (!receipt.status) { - throw new Error("Diamond cut failed."); - } + const payload = diamondCut.interface.encodeFunctionData("diamondCut", [ + cuts, + diamondInit.address, + "0x", + ]); + const tx = await proxyAdminMultisig.submitTransaction(diamondAddress, 0, payload, "0x"); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); } diff --git a/tasks/upgrade/upgradeFacets/upgradeFacets.ts b/tasks/upgrade/upgradeFacets/upgradeFacets.ts index d6ceb2590..83daeb21a 100644 --- a/tasks/upgrade/upgradeFacets/upgradeFacets.ts +++ b/tasks/upgrade/upgradeFacets/upgradeFacets.ts @@ -1,6 +1,14 @@ import {FacetCutAction} from "contracts/core/accounts/scripts/libraries/diamond"; import {task} from "hardhat/config"; -import {confirmAction, getAddresses, getSigners, isLocalNetwork, logger, verify} from "utils"; +import { + confirmAction, + connectSignerFromPkey, + getAddresses, + getSigners, + isLocalNetwork, + logger, + verify, +} from "utils"; import {ALL_FACET_NAMES} from "./constants"; import createFacetCuts from "./createFacetCuts"; import cutDiamond from "./cutDiamond"; @@ -11,6 +19,7 @@ type TaskArgs = { facets: string[]; skipVerify: boolean; yes: boolean; + proxyAdminPkey?: string; }; // Sample syntax: npx hardhat upgrade:facets --yes --network mumbai "AccountsStrategy" @@ -27,6 +36,7 @@ task("upgrade:facets", "Will redeploy and upgrade all facets that use AccountSto ) .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") .setAction(async (taskArgs: TaskArgs, hre) => { try { if (taskArgs.facets.length === 0) { @@ -42,17 +52,22 @@ task("upgrade:facets", "Will redeploy and upgrade all facets that use AccountSto return logger.out("Confirmation denied.", logger.Level.Warn); } - const {proxyAdmin} = await getSigners(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } const addresses = await getAddresses(hre); const accountsDiamond = taskArgs.accountsDiamond || addresses.accounts.diamond; - const facets = await deployFacets(facetsToUpgrade, proxyAdmin, hre); + const facets = await deployFacets(facetsToUpgrade, deployer, hre); - const facetCuts = await createFacetCuts(facets, accountsDiamond, proxyAdmin); + const facetCuts = await createFacetCuts(facets, accountsDiamond, deployer); - await cutDiamond(accountsDiamond, proxyAdmin, facetCuts, hre); + await cutDiamond(accountsDiamond, addresses.multiSig.proxyAdmin, proxyAdminSigner, facetCuts); if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { const facetsToVerify = facetCuts.filter((cut) => cut.cut.action !== FacetCutAction.Remove); diff --git a/tasks/upgrade/upgradeRegistrar.ts b/tasks/upgrade/upgradeRegistrar.ts index 3623f1abb..b8675620f 100644 --- a/tasks/upgrade/upgradeRegistrar.ts +++ b/tasks/upgrade/upgradeRegistrar.ts @@ -1,7 +1,12 @@ import {task} from "hardhat/config"; -import {Registrar__factory, ITransparentUpgradeableProxy__factory} from "typechain-types"; +import { + Registrar__factory, + ITransparentUpgradeableProxy__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -14,50 +19,69 @@ import { task("upgrade:registrar", "Will upgrade the Registrar (use only on the primary chain)") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { - try { - const isConfirmed = - taskArgs.yes || (await confirmAction("Upgrading Registrar implementation...")); - if (!isConfirmed) { - return logger.out("Confirmation denied.", logger.Level.Warn); - } - - const {deployer, proxyAdmin} = await getSigners(hre); + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") + .setAction( + async (taskArgs: {skipVerify: boolean; yes: boolean; proxyAdminPkey?: string}, hre) => { + try { + const isConfirmed = + taskArgs.yes || (await confirmAction("Upgrading Registrar implementation...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } - const addresses = await getAddresses(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } + const addresses = await getAddresses(hre); - logger.out("Deploying a new Registrar implementation..."); - const Registrar = new Registrar__factory(deployer); - const registrar = await Registrar.deploy(); - await registrar.deployed(); - logger.out(`New impl address: ${registrar.address}`); + logger.out("Deploying a new Registrar implementation..."); + const Registrar = new Registrar__factory(deployer); + const registrar = await Registrar.deploy(); + await registrar.deployed(); + logger.out(`New impl address: ${registrar.address}`); - logger.out("Upgrading Registrar proxy implementation..."); - const registrarProxy = ITransparentUpgradeableProxy__factory.connect( - addresses.registrar.proxy, - proxyAdmin - ); - const tx = await registrarProxy.upgradeTo(registrar.address); - logger.out(`Tx hash: ${tx.hash}`); - await tx.wait(); + logger.out("Upgrading Registrar proxy implementation..."); + const registrarProxy = ITransparentUpgradeableProxy__factory.connect( + addresses.registrar.proxy, + deployer + ); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const payload = registrarProxy.interface.encodeFunctionData("upgradeTo", [ + registrar.address, + ]); + const tx = await proxyAdminMultisig.submitTransaction( + registrarProxy.address, + 0, + payload, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); - await updateAddresses( - { - registrar: { - implementation: registrar.address, + await updateAddresses( + { + registrar: { + implementation: registrar.address, + }, }, - }, - hre - ); + hre + ); - if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { - await verify(hre, { - address: registrar.address, - contract: "contracts/core/registrar/Registrar.sol:Registrar", - contractName: getContractName(Registrar), - }); + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, { + address: registrar.address, + contract: "contracts/core/registrar/Registrar.sol:Registrar", + contractName: getContractName(Registrar), + }); + } + } catch (error) { + logger.out(error, logger.Level.Error); } - } catch (error) { - logger.out(error, logger.Level.Error); } - }); + ); diff --git a/tasks/upgrade/upgradeRouter.ts b/tasks/upgrade/upgradeRouter.ts index 2d81ca65f..7f38bb9c7 100644 --- a/tasks/upgrade/upgradeRouter.ts +++ b/tasks/upgrade/upgradeRouter.ts @@ -1,7 +1,12 @@ import {task} from "hardhat/config"; -import {Router__factory, ITransparentUpgradeableProxy__factory} from "typechain-types"; +import { + Router__factory, + ITransparentUpgradeableProxy__factory, + ProxyAdminMultiSig__factory, +} from "typechain-types"; import { confirmAction, + connectSignerFromPkey, getAddresses, getContractName, getSigners, @@ -14,50 +19,67 @@ import { task("upgrade:router", "Will upgrade the Router") .addFlag("skipVerify", "Skip contract verification") .addFlag("yes", "Automatic yes to prompt.") - .setAction(async (taskArgs: {skipVerify: boolean; yes: boolean}, hre) => { - try { - const isConfirmed = - taskArgs.yes || (await confirmAction("Upgrading Router implementation...")); - if (!isConfirmed) { - return logger.out("Confirmation denied.", logger.Level.Warn); - } - - const {deployer, proxyAdmin} = await getSigners(hre); + .addOptionalParam("proxyAdminPkey", "The pkey for the prod proxy admin multisig") + .setAction( + async (taskArgs: {skipVerify: boolean; yes: boolean; proxyAdminPkey?: string}, hre) => { + try { + const isConfirmed = + taskArgs.yes || (await confirmAction("Upgrading Router implementation...")); + if (!isConfirmed) { + return logger.out("Confirmation denied.", logger.Level.Warn); + } - const addresses = await getAddresses(hre); + let {deployer, proxyAdminSigner} = await getSigners(hre); + if (!proxyAdminSigner && taskArgs.proxyAdminPkey) { + proxyAdminSigner = await connectSignerFromPkey(taskArgs.proxyAdminPkey, hre); + } else if (!proxyAdminSigner) { + throw new Error("Must provide a pkey for proxyAdmin signer on this network"); + } + const addresses = await getAddresses(hre); - logger.out("Deploying a new Router implementation..."); - const Router = new Router__factory(deployer); - const router = await Router.deploy(); - await router.deployed(); - logger.out(`New impl address: ${router.address}`); + logger.out("Deploying a new Router implementation..."); + const Router = new Router__factory(deployer); + const router = await Router.deploy(); + await router.deployed(); + logger.out(`New impl address: ${router.address}`); - logger.out("Upgrading Router proxy implementation..."); - const routerProxy = ITransparentUpgradeableProxy__factory.connect( - addresses.router.proxy, - proxyAdmin - ); - const tx = await routerProxy.upgradeTo(router.address); - logger.out(`Tx hash: ${tx.hash}`); - await tx.wait(); + logger.out("Upgrading Router proxy implementation..."); + const routerProxy = ITransparentUpgradeableProxy__factory.connect( + addresses.router.proxy, + deployer + ); + const proxyAdminMultisig = ProxyAdminMultiSig__factory.connect( + addresses.multiSig.proxyAdmin, + proxyAdminSigner + ); + const payload = routerProxy.interface.encodeFunctionData("upgradeTo", [router.address]); + const tx = await proxyAdminMultisig.submitTransaction( + routerProxy.address, + 0, + payload, + "0x" + ); + logger.out(`Tx hash: ${tx.hash}`); + await tx.wait(); - await updateAddresses( - { - registrar: { - implementation: router.address, + await updateAddresses( + { + registrar: { + implementation: router.address, + }, }, - }, - hre - ); + hre + ); - if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { - await verify(hre, { - address: router.address, - contract: "contracts/core/router/Router.sol:Router", - contractName: getContractName(Router), - }); + if (!isLocalNetwork(hre) && !taskArgs.skipVerify) { + await verify(hre, { + address: router.address, + contract: "contracts/core/router/Router.sol:Router", + contractName: getContractName(Router), + }); + } + } catch (error) { + logger.out(error, logger.Level.Error); } - } catch (error) { - logger.out(error, logger.Level.Error); } - }); + ); diff --git a/test/core/IndexFund.ts b/test/core/IndexFund.ts index 5d653c9c2..6f37f2276 100644 --- a/test/core/IndexFund.ts +++ b/test/core/IndexFund.ts @@ -67,7 +67,7 @@ describe("IndexFund", function () { before(async function () { const signers = await getSigners(hre); owner = signers.deployer; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; user = signers.apTeam1; registrar = await smock.fake(new Registrar__factory()); diff --git a/test/core/accounts/AccountsAllowance.ts b/test/core/accounts/AccountsAllowance.ts index 873c29132..3df69bf8c 100644 --- a/test/core/accounts/AccountsAllowance.ts +++ b/test/core/accounts/AccountsAllowance.ts @@ -32,7 +32,7 @@ describe("AccountsAllowance", function () { before(async function () { const signers = await getSigners(hre); accOwner = signers.deployer; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; endowOwner = signers.apTeam1; user = signers.apTeam2; }); diff --git a/test/core/accounts/AccountsCreateEndowment.ts b/test/core/accounts/AccountsCreateEndowment.ts index ccd463807..063674ea1 100644 --- a/test/core/accounts/AccountsCreateEndowment.ts +++ b/test/core/accounts/AccountsCreateEndowment.ts @@ -42,7 +42,7 @@ describe("AccountsCreateEndowment", function () { before(async function () { const signers = await getSigners(hre); owner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; charityApplications = signers.deployer; const defaultSettingsPermissionsStruct = { diff --git a/test/core/accounts/AccountsDepositWithdrawEndowments.ts b/test/core/accounts/AccountsDepositWithdrawEndowments.ts index 131822ecb..eb5dcacf4 100644 --- a/test/core/accounts/AccountsDepositWithdrawEndowments.ts +++ b/test/core/accounts/AccountsDepositWithdrawEndowments.ts @@ -73,7 +73,7 @@ describe("AccountsDepositWithdrawEndowments", function () { before(async function () { const signers = await getSigners(hre); accOwner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; endowOwner = signers.deployer; indexFund = signers.apTeam2; diff --git a/test/core/accounts/AccountsGasManager.ts b/test/core/accounts/AccountsGasManager.ts index 5e8312ba1..d1318ec6a 100644 --- a/test/core/accounts/AccountsGasManager.ts +++ b/test/core/accounts/AccountsGasManager.ts @@ -36,7 +36,7 @@ describe("AccountsGasManager", function () { before(async function () { const signers = await getSigners(hre); owner = signers.deployer; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; user = signers.apTeam1; let Facet = new AccountsGasManager__factory(owner); impl = await Facet.deploy(); diff --git a/test/core/accounts/AccountsQueryEndowments.ts b/test/core/accounts/AccountsQueryEndowments.ts index f0b375258..3bcbded5b 100644 --- a/test/core/accounts/AccountsQueryEndowments.ts +++ b/test/core/accounts/AccountsQueryEndowments.ts @@ -43,7 +43,7 @@ describe("AccountsQueryEndowments", function () { before(async function () { const signers = await getSigners(hre); owner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; tokenAddress = signers.deployer.address; const Facet = new AccountsQueryEndowments__factory(owner); diff --git a/test/core/accounts/AccountsStrategy.ts b/test/core/accounts/AccountsStrategy.ts index 7f3ee89b2..dddd417e4 100644 --- a/test/core/accounts/AccountsStrategy.ts +++ b/test/core/accounts/AccountsStrategy.ts @@ -83,9 +83,9 @@ describe("AccountsStrategy", function () { let endowDetails: AccountStorage.EndowmentStruct; before(async function () { - const {deployer, proxyAdmin, apTeam1} = await getSigners(hre); + const {deployer, proxyAdminSigner, apTeam1} = await getSigners(hre); owner = deployer; - admin = proxyAdmin; + admin = proxyAdminSigner!; user = apTeam1; gasService = await smock.fake(IAxelarGasService__factory.createInterface()); diff --git a/test/core/accounts/AccountsSwapRouter.ts b/test/core/accounts/AccountsSwapRouter.ts index c34a47785..6962fec0c 100644 --- a/test/core/accounts/AccountsSwapRouter.ts +++ b/test/core/accounts/AccountsSwapRouter.ts @@ -47,7 +47,7 @@ describe("AccountsSwapRouter", function () { before(async function () { const signers = await getSigners(hre); owner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; user = signers.deployer; let Facet = new AccountsSwapRouter__factory(owner); diff --git a/test/core/accounts/AccountsUpdate.ts b/test/core/accounts/AccountsUpdate.ts index 10e235b9a..daa567d84 100644 --- a/test/core/accounts/AccountsUpdate.ts +++ b/test/core/accounts/AccountsUpdate.ts @@ -23,10 +23,10 @@ describe("AccountsUpdate", function () { before(async function () { const signers = await getSigners(hre); owner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; user = signers.deployer; - newRegistrar = signers.airdropOwner.address; + newRegistrar = signers.apTeam1.address; endowment = {...DEFAULT_CHARITY_ENDOWMENT, owner: owner.address}; }); diff --git a/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts b/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts index 16c8febea..12a3f7413 100644 --- a/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts +++ b/test/core/accounts/AccountsUpdateEndowmentSettingsController.ts @@ -38,7 +38,7 @@ describe("AccountsUpdateEndowmentSettingsController", function () { before(async function () { const signers = await getSigners(hre); owner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; endowOwner = signers.deployer; charity = { diff --git a/test/core/accounts/AccountsUpdateEndowments.ts b/test/core/accounts/AccountsUpdateEndowments.ts index 12f76fb3f..e7be7e579 100644 --- a/test/core/accounts/AccountsUpdateEndowments.ts +++ b/test/core/accounts/AccountsUpdateEndowments.ts @@ -42,7 +42,7 @@ describe("AccountsUpdateEndowments", function () { before(async function () { const signers = await getSigners(hre); accOwner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; endowOwner = signers.deployer; delegate = signers.apTeam2; diff --git a/test/core/accounts/AccountsUpdateStatusEndowments.ts b/test/core/accounts/AccountsUpdateStatusEndowments.ts index 8d682fd1f..3022afed5 100644 --- a/test/core/accounts/AccountsUpdateStatusEndowments.ts +++ b/test/core/accounts/AccountsUpdateStatusEndowments.ts @@ -61,7 +61,7 @@ describe("AccountsUpdateStatusEndowments", function () { before(async function () { const signers = await getSigners(hre); accOwner = signers.apTeam1; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; endowOwner = signers.deployer; treasuryAddress = signers.apTeam2.address; diff --git a/test/core/gasFwd/GasFwd.ts b/test/core/gasFwd/GasFwd.ts index f6ab69b88..d3dc492ae 100644 --- a/test/core/gasFwd/GasFwd.ts +++ b/test/core/gasFwd/GasFwd.ts @@ -41,9 +41,9 @@ describe("GasFwd", function () { } before(async function () { - const {deployer, proxyAdmin, apTeam1} = await getSigners(hre); + const {deployer, proxyAdminSigner, apTeam1} = await getSigners(hre); owner = deployer; - admin = proxyAdmin; + admin = proxyAdminSigner!; accounts = apTeam1; }); diff --git a/test/core/gasFwd/GasFwdFactory.ts b/test/core/gasFwd/GasFwdFactory.ts index 49b021b05..73add7cb0 100644 --- a/test/core/gasFwd/GasFwdFactory.ts +++ b/test/core/gasFwd/GasFwdFactory.ts @@ -36,9 +36,9 @@ describe("GasFwdFactory", function () { } before(async function () { - const {deployer, proxyAdmin, apTeam1} = await getSigners(hre); + const {deployer, proxyAdminSigner, apTeam1} = await getSigners(hre); owner = deployer; - admin = proxyAdmin; + admin = proxyAdminSigner!; user = apTeam1; }); diff --git a/test/core/registrar/LocalRegistrar.ts b/test/core/registrar/LocalRegistrar.ts index 6bd0dcc3f..42912a309 100644 --- a/test/core/registrar/LocalRegistrar.ts +++ b/test/core/registrar/LocalRegistrar.ts @@ -39,7 +39,7 @@ describe("Local Registrar", function () { async function deployRegistrarAsProxy(): Promise { const signers = await getSigners(hre); - owner = signers.proxyAdmin; + owner = signers.proxyAdminSigner!; user = signers.apTeam1; Registrar = (await ethers.getContractFactory( diff --git a/test/core/router/Router.ts b/test/core/router/Router.ts index 6c5346879..6888334e0 100644 --- a/test/core/router/Router.ts +++ b/test/core/router/Router.ts @@ -40,9 +40,9 @@ describe("Router", function () { const accountsContract = deadAddr; before(async function () { - const {deployer, proxyAdmin, apTeam1, apTeam2} = await getSigners(hre); + const {deployer, proxyAdminSigner, apTeam1, apTeam2} = await getSigners(hre); owner = deployer; - admin = proxyAdmin; + admin = proxyAdminSigner!; user = apTeam1; collector = apTeam2; }); diff --git a/test/core/vault/Vault.ts b/test/core/vault/Vault.ts index 48daed31d..90d5a6859 100644 --- a/test/core/vault/Vault.ts +++ b/test/core/vault/Vault.ts @@ -82,9 +82,9 @@ describe("Vault", function () { } before(async function () { - const {deployer, proxyAdmin, apTeam1, apTeam2} = await getSigners(hre); + const {deployer, proxyAdminSigner, apTeam1, apTeam2} = await getSigners(hre); owner = deployer; - admin = proxyAdmin; + admin = proxyAdminSigner!; user = apTeam1; collector = apTeam2; diff --git a/test/halo/Halo.ts b/test/halo/Halo.ts index c833131b9..b3fa05309 100644 --- a/test/halo/Halo.ts +++ b/test/halo/Halo.ts @@ -19,7 +19,7 @@ describe("Halo token", function () { beforeEach(async function () { const signers = await getSigners(hre); deployer = signers.deployer; - proxyAdmin = signers.proxyAdmin; + proxyAdmin = signers.proxyAdminSigner!; user = signers.apTeam1; Halo = (await hre.ethers.getContractFactory("Halo", proxyAdmin)) as Halo__factory; diff --git a/utils/env.config.ts b/utils/env.config.ts index b4e1dadcd..f64f81c86 100644 --- a/utils/env.config.ts +++ b/utils/env.config.ts @@ -2,11 +2,10 @@ import {config as dotenvConfig} from "dotenv"; import {resolve} from "path"; import {HardhatNetworkAccountsUserConfig, HardhatNetworkAccountUserConfig} from "hardhat/types"; +import {Signer, EnvConfig} from "./types"; dotenvConfig({path: resolve(__dirname, "../.env")}); -type Signer = {key: string; address: string}; - const AP_TEAM_1: Signer = { key: extractString("AP_TEAM_1_KEY"), address: extractString("AP_TEAM_1_ADDRESS"), @@ -27,7 +26,7 @@ const DEPLOYER: Signer = { address: extractString("DEPLOYER_ADDRESS"), }; -const PROXY_ADMIN: Signer = { +const PROXY_ADMIN_DEV: Signer = { key: extractString("PROXY_ADMIN_KEY"), address: extractString("PROXY_ADMIN_ADDRESS"), }; @@ -38,23 +37,8 @@ const GANACHE_PRIVATE_KEY = extractString("GANACHE_PRIVATE_KEY"); const GANACHE_RPC_URL = extractString("GANACHE_RPC_URL"); const MAINNET_RPC_URL = extractString("MAINNET_URL"); const MUMBAI_RPC_URL = extractString("MUMBAI_RPC_URL"); -const NETWORK = extractString("NETWORK"); -const OPTIMIZER_FLAG = extractString("OPTIMIZER_FLAG"); -const OPTIMIZER_RUNS = extractNumber("OPTIMIZER_RUNS"); const POLYGON_RPC_URL = extractString("POLYGON_RPC_URL"); const POLYSCAN_API_KEY = extractString("POLYSCAN_API_KEY"); -const VERIFY_CONTRACTS = extractString("VERIFY_CONTRACTS"); - -function extractNumber(name: string): number { - const envVar = extractString(name); - - const numVar = Number(envVar); - if (isNaN(numVar)) { - throw new Error(`Please add ${name} key with a number value to your .env file`); - } - - return numVar; -} function extractString(name: string): string { const envVar = process.env[name]; @@ -65,32 +49,34 @@ function extractString(name: string): string { } export function getHardhatAccounts(accountList: string[]): HardhatNetworkAccountsUserConfig { - let hardhatAccounts: HardhatNetworkAccountUserConfig[] = []; - accountList.forEach((element) => { - hardhatAccounts.push({ - privateKey: element, - balance: "1000000000000000000000", - }); - }); + const hardhatAccounts: HardhatNetworkAccountUserConfig[] = accountList.map((element) => ({ + privateKey: element, + balance: "1000000000000000000000", + })); return hardhatAccounts; } -export var envConfig = { - AP_TEAM_1, - AP_TEAM_2, - AP_TEAM_3, - DEPLOYER, - PROXY_ADMIN, +export const envConfigDev: EnvConfig = { + ETHERSCAN_API_KEY, + GANACHE_PRIVATE_KEY, + GANACHE_RPC_URL, + GOERLI_RPC_URL, + MAINNET_RPC_URL, + MUMBAI_RPC_URL, + POLYGON_RPC_URL, + POLYSCAN_API_KEY, + // order of account items is important! + ACCOUNTS: [DEPLOYER.key, PROXY_ADMIN_DEV.key, AP_TEAM_1.key, AP_TEAM_2.key, AP_TEAM_3.key], +}; + +export const envConfigProd: EnvConfig = { ETHERSCAN_API_KEY, GANACHE_PRIVATE_KEY, GANACHE_RPC_URL, GOERLI_RPC_URL, MAINNET_RPC_URL, MUMBAI_RPC_URL, - NETWORK, - OPTIMIZER_FLAG, - OPTIMIZER_RUNS, POLYGON_RPC_URL, POLYSCAN_API_KEY, - VERIFY_CONTRACTS, + ACCOUNTS: [DEPLOYER.key, AP_TEAM_1.key, AP_TEAM_2.key, AP_TEAM_3.key], }; diff --git a/utils/getSigners.ts b/utils/getSigners.ts index c86dca858..501df6d83 100644 --- a/utils/getSigners.ts +++ b/utils/getSigners.ts @@ -1,32 +1,54 @@ import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +import {Wallet} from "ethers"; import {HardhatRuntimeEnvironment} from "hardhat/types"; +import {isProdNetwork} from "./networkHelpers"; type Result = { - airdropOwner: SignerWithAddress; + airdropOwner?: SignerWithAddress; apTeam1: SignerWithAddress; apTeam2: SignerWithAddress; apTeam3: SignerWithAddress; - charityApplicationsOwners: SignerWithAddress[]; - apTeamMultisigOwners: SignerWithAddress[]; + charityApplicationsOwners?: SignerWithAddress[]; + apTeamMultisigOwners?: SignerWithAddress[]; + proxyAdminMultisigOwners?: SignerWithAddress[]; deployer: SignerWithAddress; - proxyAdmin: SignerWithAddress; - timeLockAdmin: SignerWithAddress; - treasury: SignerWithAddress; + proxyAdminSigner?: SignerWithAddress; + timeLockAdmin?: SignerWithAddress; + treasury?: SignerWithAddress; }; export async function getSigners(hre: HardhatRuntimeEnvironment): Promise { - const [deployer, proxyAdmin, apTeam1, apTeam2, apTeam3] = await hre.ethers.getSigners(); + if (await isProdNetwork(hre)) { + const [deployer, apTeam1, apTeam2, apTeam3] = await hre.ethers.getSigners(); + return { + deployer, + apTeam1, + apTeam2, + apTeam3, + }; + } else { + const [deployer, proxyAdminSigner, apTeam1, apTeam2, apTeam3] = await hre.ethers.getSigners(); - return { - airdropOwner: apTeam1, - apTeam1, - apTeam2, - apTeam3, - charityApplicationsOwners: [apTeam2, apTeam3], - apTeamMultisigOwners: [apTeam1, apTeam2], - deployer, - proxyAdmin, - treasury: apTeam1, - timeLockAdmin: apTeam1, - }; + return { + airdropOwner: apTeam1, + apTeam1, + apTeam2, + apTeam3, + charityApplicationsOwners: [apTeam2, apTeam3], + apTeamMultisigOwners: [apTeam1, apTeam2], + proxyAdminMultisigOwners: [proxyAdminSigner], + deployer, + proxyAdminSigner, + treasury: apTeam1, + timeLockAdmin: apTeam1, + }; + } +} + +export async function connectSignerFromPkey( + pkey: string, + hre: HardhatRuntimeEnvironment +): Promise { + const signer = new Wallet(pkey, hre.ethers.provider); + return hre.ethers.getSigner(signer.address); } diff --git a/utils/manageAddressFile/helpers.ts b/utils/manageAddressFile/helpers.ts index a147c188e..116260300 100644 --- a/utils/manageAddressFile/helpers.ts +++ b/utils/manageAddressFile/helpers.ts @@ -175,6 +175,7 @@ export function createEmptyAddressObj(): AddressObj { factory: "", implementation: "", }, + proxyAdmin: "", }, registrar: { implementation: "", diff --git a/utils/manageAddressFile/manageAddressFile.ts b/utils/manageAddressFile/manageAddressFile.ts index 2f620117f..e8185ea75 100644 --- a/utils/manageAddressFile/manageAddressFile.ts +++ b/utils/manageAddressFile/manageAddressFile.ts @@ -7,20 +7,22 @@ import {AddressObj} from "./types"; /** * Removes contract address for the current network from the appropriate file. */ -export async function resetAddresses( +export async function resetContractAddresses( hre: HardhatRuntimeEnvironment, filePath = DEFAULT_CONTRACT_ADDRESS_FILE_PATH ) { const chainId = await getChainId(hre); + const emptyAddressObj = createEmptyAddressObj(); + if (isLocalNetwork(hre)) { - return saveFrontendFiles({[chainId]: createEmptyAddressObj()}, filePath); + return saveFrontendFiles({[chainId]: emptyAddressObj}, filePath); } const currentAddressObj = getAddressesByNetworkId(chainId, filePath); const cleaned: AddressObj = { - ...createEmptyAddressObj(), + ...emptyAddressObj, axelar: currentAddressObj.axelar, tokens: {...currentAddressObj.tokens, halo: "", reserveToken: ""}, uniswap: currentAddressObj.uniswap, diff --git a/utils/manageAddressFile/types.ts b/utils/manageAddressFile/types.ts index 9092d04af..0e49f07dd 100644 --- a/utils/manageAddressFile/types.ts +++ b/utils/manageAddressFile/types.ts @@ -107,6 +107,7 @@ export type AddressObj = { factory: string; implementation: string; }; + proxyAdmin: string; }; registrar: { implementation: string; diff --git a/utils/networkHelpers.ts b/utils/networkHelpers.ts index f08cfdd94..b053c2f27 100644 --- a/utils/networkHelpers.ts +++ b/utils/networkHelpers.ts @@ -1,6 +1,18 @@ -import {HardhatRuntimeEnvironment, Network} from "hardhat/types"; +import {HardhatRuntimeEnvironment} from "hardhat/types"; import {TwoWayMap} from "./twoWayMap"; +const PROD_NETWORKS = [1, 137]; // Ethereum, Polygon + +// There are errors/mismatches in the axelar sdk jsons, so we just implement a lightweight +// version here and use this instead. +const AxelarNetworks = new TwoWayMap({ + 1: "Ethereum", + 5: "ethereum-2", + 137: "Polygon", + 31337: "localhost", + 80001: "Polygon", +}); + export function isLocalNetwork(hre: HardhatRuntimeEnvironment) { return hre.network.name === "hardhat" || hre.network.name === "localhost"; } @@ -27,12 +39,7 @@ export async function getChainId(hre: HardhatRuntimeEnvironment): Promise { + const thisChainId = await getChainId(hre); + return PROD_NETWORKS.includes(thisChainId); +} diff --git a/utils/types/env.ts b/utils/types/env.ts new file mode 100644 index 000000000..fe5a0d96e --- /dev/null +++ b/utils/types/env.ts @@ -0,0 +1,13 @@ +export type Signer = {key: string; address: string}; + +export type EnvConfig = { + ETHERSCAN_API_KEY: string; + GANACHE_PRIVATE_KEY: string; + GANACHE_RPC_URL: string; + GOERLI_RPC_URL: string; + MAINNET_RPC_URL: string; + MUMBAI_RPC_URL: string; + POLYGON_RPC_URL: string; + POLYSCAN_API_KEY: string; + ACCOUNTS: string[]; +}; diff --git a/utils/types/index.ts b/utils/types/index.ts index b5c59a32f..3c413d248 100644 --- a/utils/types/index.ts +++ b/utils/types/index.ts @@ -1,2 +1,3 @@ export * from "./common"; export * from "./enums"; +export * from "./env";