diff --git a/.eslint-tsconfig b/.eslint-tsconfig index f3d56b89b..7cf6ed892 100644 --- a/.eslint-tsconfig +++ b/.eslint-tsconfig @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "include": ["jest.config.js", ".eslintrc.js", "tests", "scenario", "deploy", "docgen-templates", "commitlint.config.js", "./hardhat.config.zksync.ts"] + "include": ["jest.config.js", ".eslintrc.js", "tests", "scenario", "deploy", "docgen-templates", "commitlint.config.js", "./hardhat.config.zksync.ts", "type-extensions.ts"] } diff --git a/README.md b/README.md index 48cc9cc89..9b5d1b7d3 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,15 @@ npx hardhat deploy - In the deployment scripts you have added `tags` for example: - `func.tags = ["MockTokens"];` - Once this is done, adding `--tags ",..."` to the deployment command will execute only the scripts containing the tags. +### Dry Run / Forked Deployments +To simulate what contracts would be deployed on a given network the deployment scripts support running on a forked network. To run the deployment scripts on a forked network the `HARDHAT_FORK_NETWORK` env variable needs to be set. + +For example +```bash +HARDHAT_FORK_NETWORK=ethereum npx hardhat deploy +``` + + ### Deployed Contracts Deployed contract abis and addresses are exported in the `deployments` directory. To create a summary export of all contracts deployed to a network run diff --git a/deploy/001-deploy-mock-tokens.ts b/deploy/001-deploy-mock-tokens.ts index 27cdd0a2a..d4ba52349 100644 --- a/deploy/001-deploy-mock-tokens.ts +++ b/deploy/001-deploy-mock-tokens.ts @@ -4,11 +4,11 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { getConfig } from "../helpers/deploymentConfig"; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployments, getNamedAccounts }: any = hre; + const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { tokensConfig } = await getConfig(hre.network.name); + const { tokensConfig } = await getConfig(hre.getNetworkName()); for (const token of tokensConfig) { if (token.isMock) { @@ -27,4 +27,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { func.tags = ["MockTokens"]; +func.skip = async hre => hre.network.live; + export default func; diff --git a/deploy/004-swap-router.ts b/deploy/004-swap-router.ts index 498776ce9..211b91d5a 100644 --- a/deploy/004-swap-router.ts +++ b/deploy/004-swap-router.ts @@ -16,7 +16,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const vbnbAddress = (await deployments.get("vBNB")).address; // Pancake Factory doesn't exist on hardhat so we are using the testnet address const pancakeFactoryAddress = - hre.network.name === "bscmainnet" + hre.getNetworkName() === "bscmainnet" ? Mainnet.contracts.pancakeFactory.address : Testnet.contracts.pancakeFactory.address; @@ -48,7 +48,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { autoMine: true, skipIfAlreadyDeployed: true, }); - if (hre.network.name !== "bsctestnet") { + if (hre.getNetworkName() !== "bsctestnet") { const comptrollerStablecoinsAddresses = (await deployments.get("Comptroller_Stablecoins")).address; await deploy("SwapRouter_Stablecoins", { contract: "SwapRouter", @@ -95,10 +95,10 @@ func.tags = ["SwapRouter", "il"]; // deploySwapRouter.skip = async (hre: HardhatRuntimeEnvironment) => hre.network.live; // Pancake Factory is not deployed on the local network func.skip = async hre => - hre.network.name === "sepolia" || - hre.network.name === "hardhat" || - hre.network.name === "opbnbtestnet" || - hre.network.name === "opbnbmainnet" || - hre.network.name === "ethereum"; + hre.getNetworkName() === "sepolia" || + hre.getNetworkName() === "hardhat" || + hre.getNetworkName() === "opbnbtestnet" || + hre.getNetworkName() === "opbnbmainnet" || + hre.getNetworkName() === "ethereum"; export default func; diff --git a/deploy/006-deploy-pool-registry.ts b/deploy/006-deploy-pool-registry.ts index 4958efe38..1c23dbb93 100644 --- a/deploy/006-deploy-pool-registry.ts +++ b/deploy/006-deploy-pool-registry.ts @@ -8,12 +8,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { preconfiguredAddresses } = await getConfig(hre.network.name); + const { preconfiguredAddresses } = await getConfig(hre.getNetworkName()); const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); - const proxyOwnerAddress = await toAddress(preconfiguredAddresses.NormalTimelock || "account:deployer", hre); + const proxyOwnerAddress = await toAddress(preconfiguredAddresses.NormalTimelock || "account:deployer"); // The reason for this is that the contracts `OptimizedTransparentUpgradeableProxy` and `DefaultProxyAdmin` that the hardhat-deploy // plugin fetches from the artifact is not zk compatible causing the deployments to fail. So we bought it one level up to our repo, diff --git a/deploy/007-deploy-pool-lens.ts b/deploy/007-deploy-pool-lens.ts index 2ccd22246..0c204f7ef 100644 --- a/deploy/007-deploy-pool-lens.ts +++ b/deploy/007-deploy-pool-lens.ts @@ -8,7 +8,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); + const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.getNetworkName()); await deploy("PoolLens", { from: deployer, diff --git a/deploy/008-deploy-comptrollers.ts b/deploy/008-deploy-comptrollers.ts index 89bdd15c7..c16f7c596 100644 --- a/deploy/008-deploy-comptrollers.ts +++ b/deploy/008-deploy-comptrollers.ts @@ -10,12 +10,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const deploymentConfig = await getConfig(hre.network.name); + const deploymentConfig = await getConfig(hre.getNetworkName()); const { poolConfig, preconfiguredAddresses } = deploymentConfig; const poolRegistry = await ethers.getContract("PoolRegistry"); const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); const maxLoopsLimit = 100; @@ -37,12 +36,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { skipIfAlreadyDeployed: true, }); - const unregisteredPools = await getUnregisteredPools(poolConfig, hre); + const unregisteredPools = await getUnregisteredPools(poolConfig); for (const pool of unregisteredPools) { - // Deploying a proxy for Comptroller - console.log(`Deploying a proxy for Comptroller of the pool ${pool.name}`); const Comptroller = await ethers.getContractFactory("Comptroller"); + // Deploying a proxy for Comptroller await deploy(`Comptroller_${pool.id}`, { from: deployer, contract: "BeaconProxy", diff --git a/deploy/009-deploy-vtokens.ts b/deploy/009-deploy-vtokens.ts index d7c6b9fce..72122ac99 100644 --- a/deploy/009-deploy-vtokens.ts +++ b/deploy/009-deploy-vtokens.ts @@ -19,14 +19,13 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { tokensConfig, poolConfig, preconfiguredAddresses } = await getConfig(hre.network.name); + const { tokensConfig, poolConfig, preconfiguredAddresses } = await getConfig(hre.getNetworkName()); - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); - const maxBorrowRateMantissa = getMaxBorrowRateMantissa(hre.network.name); + const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.getNetworkName()); + const maxBorrowRateMantissa = getMaxBorrowRateMantissa(hre.getNetworkName()); const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); // VToken Beacon @@ -48,7 +47,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { skipIfAlreadyDeployed: true, }); - const poolsWithUnregisteredVTokens = await getUnregisteredVTokens(poolConfig, hre); + const poolsWithUnregisteredVTokens = await getUnregisteredVTokens(poolConfig); for (const pool of poolsWithUnregisteredVTokens) { const comptrollerProxy = await ethers.getContract(`Comptroller_${pool.id}`); @@ -81,7 +80,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { if (rateModel === InterestRateModels.JumpRate.toString()) { const [b, m, j, k] = [baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_].map(mantissaToBps); const rateModelName = `JumpRateModelV2_base${b}bps_slope${m}bps_jump${j}bps_kink${k}bps`; - console.log(`Deploying interest rate model ${rateModelName}`); const result: DeployResult = await deploy(rateModelName, { from: deployer, contract: "JumpRateModelV2", @@ -102,7 +100,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } else { const [b, m] = [baseRatePerYear, multiplierPerYear].map(mantissaToBps); const rateModelName = `WhitePaperInterestRateModel_base${b}bps_slope${m}bps`; - console.log(`Deploying interest rate model ${rateModelName}`); const result: DeployResult = await deploy(rateModelName, { from: deployer, contract: "WhitePaperInterestRateModel", @@ -114,7 +111,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { rateModelAddress = result.address; } - console.log(`Deploying VToken proxy for ${symbol}`); const VToken = await ethers.getContractFactory("VToken"); const underlyingDecimals = Number(await tokenContract.decimals()); const vTokenDecimals = 8; diff --git a/deploy/010-deploy-reward-distributors.ts b/deploy/010-deploy-reward-distributors.ts index f146597ba..780681634 100644 --- a/deploy/010-deploy-reward-distributors.ts +++ b/deploy/010-deploy-reward-distributors.ts @@ -15,19 +15,16 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployer } = await getNamedAccounts(); const maxLoopsLimit = 100; - const { tokensConfig, poolConfig, preconfiguredAddresses } = await getConfig(hre.network.name); - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); + const { tokensConfig, poolConfig, preconfiguredAddresses } = await getConfig(hre.getNetworkName()); + const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.getNetworkName()); - const accessControlAddress = await toAddress( - preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, - ); - const proxyOwnerAddress = await toAddress(preconfiguredAddresses.NormalTimelock || "account:deployer", hre); + const accessControlAddress = await toAddress(preconfiguredAddresses.AccessControlManager || "AccessControlManager"); + const proxyOwnerAddress = await toAddress(preconfiguredAddresses.NormalTimelock || "account:deployer"); const defaultProxyAdmin = await hre.artifacts.readArtifact( "hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol:ProxyAdmin", ); - const pools = await getUnregisteredRewardsDistributors(poolConfig, hre); + const pools = await getUnregisteredRewardsDistributors(poolConfig); await deploy("RewardsDistributorImpl", { contract: "RewardsDistributor", diff --git a/deploy/011-initial-liquidity.ts b/deploy/011-initial-liquidity.ts index bd36fa462..54a509529 100644 --- a/deploy/011-initial-liquidity.ts +++ b/deploy/011-initial-liquidity.ts @@ -1,4 +1,5 @@ import { BigNumber } from "ethers"; +import { getNetworkName } from "hardhat"; import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; @@ -20,9 +21,9 @@ const sumAmounts = async (tokens: { symbol: string; amount: BigNumber }[]) => { return amounts; }; -const faucetTokens = async (deploymentConfig: DeploymentConfig, hre: HardhatRuntimeEnvironment) => { +const faucetTokens = async (deploymentConfig: DeploymentConfig) => { const { poolConfig, tokensConfig } = deploymentConfig; - const unregisteredVTokens = await getUnregisteredVTokens(poolConfig, hre); + const unregisteredVTokens = await getUnregisteredVTokens(poolConfig); const vTokenConfigs = unregisteredVTokens.map((p: PoolConfig) => p.vtokens).flat(); const assetsToFaucet = vTokenConfigs .map((v: { asset: string }) => getTokenConfig(v.asset, tokensConfig)) @@ -42,17 +43,17 @@ const faucetTokens = async (deploymentConfig: DeploymentConfig, hre: HardhatRunt const tx = await tokenContract.faucet(amount, { gasLimit: 5000000 }); await tx.wait(1); } + return vTokensToFaucet; }; -const sendInitialLiquidityToTreasury = async (deploymentConfig: DeploymentConfig, hre: HardhatRuntimeEnvironment) => { - if (hre.network.name == "bscmainnet" || hre.network.name == "ethereum") { +const sendInitialLiquidityToTreasury = async (deploymentConfig: DeploymentConfig, tokensToFaucet: VTokenConfig[]) => { + if (getNetworkName() == "bscmainnet" || getNetworkName() == "ethereum") { return; } - const { poolConfig, tokensConfig, preconfiguredAddresses } = deploymentConfig; - const unregisteredVTokens = await getUnregisteredVTokens(poolConfig, hre); - const vTokenConfigs = unregisteredVTokens.map((p: PoolConfig) => p.vtokens).flat(); - const amounts = vTokenConfigs.map((token: VTokenConfig) => ({ + const { tokensConfig, preconfiguredAddresses } = deploymentConfig; + + const amounts = tokensToFaucet.map((token: VTokenConfig) => ({ symbol: token.asset, amount: BigNumber.from(token.initialSupply), })); @@ -60,10 +61,7 @@ const sendInitialLiquidityToTreasury = async (deploymentConfig: DeploymentConfig for (const [symbol, amount] of Object.entries(totalAmounts)) { const tokenContract = await getUnderlyingToken(symbol, tokensConfig); console.log(`Sending ${amount} ${symbol} to VTreasury`); - console.log(`Token Contract: ${tokenContract.address}`); - console.log(`Token Contract: ${amount.toString()}`); - const treasuryAddress = await toAddress(preconfiguredAddresses.VTreasury || "VTreasury", hre); - console.log(`Token Contract: ${treasuryAddress}`); + const treasuryAddress = await toAddress(preconfiguredAddresses.VTreasury || "VTreasury"); const tx = await tokenContract.transfer(treasuryAddress, amount, { gasLimit: 5000000 }); await tx.wait(1); @@ -71,9 +69,9 @@ const sendInitialLiquidityToTreasury = async (deploymentConfig: DeploymentConfig }; const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const deploymentConfig = await getConfig(hre.network.name); - await faucetTokens(deploymentConfig, hre); - await sendInitialLiquidityToTreasury(deploymentConfig, hre); + const deploymentConfig = await getConfig(hre.getNetworkName()); + const assetsToFaucet = await faucetTokens(deploymentConfig); + await sendInitialLiquidityToTreasury(deploymentConfig, assetsToFaucet); }; func.tags = ["InitialLiquidity", "il"]; diff --git a/deploy/012-transfer-pools-ownership.ts b/deploy/012-transfer-pools-ownership.ts index c51c1ff1a..01e97f3d1 100644 --- a/deploy/012-transfer-pools-ownership.ts +++ b/deploy/012-transfer-pools-ownership.ts @@ -4,29 +4,6 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { PoolConfig, getConfig } from "../helpers/deploymentConfig"; -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployer } = await getNamedAccounts(); - const { poolConfig, preconfiguredAddresses } = await getConfig(hre.network.name); - const targetOwner = preconfiguredAddresses.NormalTimelock || deployer; - - const rewardsDistributors = poolConfig - .map((pool: PoolConfig) => { - const rewards = pool.rewards || []; - return rewards.map((_, idx: number) => `RewardsDistributor_${pool.id}_${idx}`); - }) - .flat(); - - const comptrollers = poolConfig.map((pool: PoolConfig) => `Comptroller_${pool.id}`); - - const contracts = { - singleStepOwnership: ["ComptrollerBeacon", "VTokenBeacon"], - twoStepOwnership: ["PoolRegistry", ...comptrollers, ...rewardsDistributors], - }; - - await transferSingleStepOwnerships(contracts.singleStepOwnership, targetOwner); - await transfer2StepOwnerships(contracts.twoStepOwnership, targetOwner); -}; - const transfer2StepOwnerships = async (contractNames: string[], targetOwner: string) => { const abi = [ "function owner() view returns (address)", @@ -70,6 +47,29 @@ const transferSingleStepOwnerships = async (contractNames: string[], targetOwner } }; +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { deployer } = await getNamedAccounts(); + const { poolConfig, preconfiguredAddresses } = await getConfig(hre.getNetworkName()); + const targetOwner = preconfiguredAddresses.NormalTimelock || deployer; + + const rewardsDistributors = poolConfig + .map((pool: PoolConfig) => { + const rewards = pool.rewards || []; + return rewards.map((_, idx: number) => `RewardsDistributor_${pool.id}_${idx}`); + }) + .flat(); + + const comptrollers = poolConfig.map((pool: PoolConfig) => `Comptroller_${pool.id}`); + + const contracts = { + singleStepOwnership: ["ComptrollerBeacon", "VTokenBeacon"], + twoStepOwnership: ["PoolRegistry", ...comptrollers, ...rewardsDistributors], + }; + + await transferSingleStepOwnerships(contracts.singleStepOwnership, targetOwner); + await transfer2StepOwnerships(contracts.twoStepOwnership, targetOwner); +}; + func.tags = ["TransferPoolsOwnership", "il"]; func.id = "transfer_pools_ownership"; // id required to prevent re-execution export default func; diff --git a/deploy/013-vip-based-config.ts b/deploy/013-vip-based-config.ts index acaf7f6af..6204d25be 100644 --- a/deploy/013-vip-based-config.ts +++ b/deploy/013-vip-based-config.ts @@ -1,6 +1,6 @@ import { BigNumberish } from "ethers"; import { defaultAbiCoder, parseEther } from "ethers/lib/utils"; -import { ethers } from "hardhat"; +import { deployments, ethers, network } from "hardhat"; import { DeployFunction } from "hardhat-deploy/types"; import { HardhatRuntimeEnvironment } from "hardhat/types"; @@ -76,7 +76,6 @@ const setRewardSpeed = async ( const configureRewards = async ( unregisteredRewardDistributors: PoolConfig[], owner: string, - hre: HardhatRuntimeEnvironment, ): Promise => { const commands = await Promise.all( unregisteredRewardDistributors.map(async (pool: PoolConfig) => { @@ -86,7 +85,7 @@ const configureRewards = async ( const contractName = `RewardsDistributor_${pool.id}_${idx}`; const rewardsDistributor = await ethers.getContract(contractName); return [ - ...(await acceptOwnership(contractName, owner, hre)), + ...(await acceptOwnership(contractName, owner)), await addRewardsDistributor(rewardsDistributor, pool, rewardConfig), await setRewardSpeed(pool, rewardsDistributor, rewardConfig), ]; @@ -98,16 +97,12 @@ const configureRewards = async ( return commands.flat(); }; -const acceptOwnership = async ( - contractName: string, - targetOwner: string, - hre: HardhatRuntimeEnvironment, -): Promise => { - if (!hre.network.live) { +const acceptOwnership = async (contractName: string, targetOwner: string): Promise => { + if (!network.live) { return []; } const abi = ["function owner() view returns (address)"]; - const deployment = await hre.deployments.get(contractName); + const deployment = await deployments.get(contractName); const contract = await ethers.getContractAt(abi, deployment.address); if ((await contract.owner()) === targetOwner) { return []; @@ -153,17 +148,13 @@ const addPool = (poolRegistry: PoolRegistry, comptroller: Comptroller, pool: Poo }; }; -const addPools = async ( - unregisteredPools: PoolConfig[], - poolsOwner: string, - hre: HardhatRuntimeEnvironment, -): Promise => { +const addPools = async (unregisteredPools: PoolConfig[], poolsOwner: string): Promise => { const poolRegistry = await ethers.getContract("PoolRegistry"); const commands = await Promise.all( unregisteredPools.map(async (pool: PoolConfig) => { const comptroller = await ethers.getContract(`Comptroller_${pool.id}`); return [ - ...(await acceptOwnership(`Comptroller_${pool.id}`, poolsOwner, hre)), + ...(await acceptOwnership(`Comptroller_${pool.id}`, poolsOwner)), await setOracle(comptroller, pool), addPool(poolRegistry, comptroller, pool), ]; @@ -175,9 +166,8 @@ const addPools = async ( const transferInitialLiquidity = async ( vTokenConfig: VTokenConfig, deploymentConfig: DeploymentConfig, - hre: HardhatRuntimeEnvironment, ): Promise => { - if (!hre.network.live) { + if (!network.live) { return []; } const { preconfiguredAddresses, tokensConfig } = deploymentConfig; @@ -229,11 +219,10 @@ const addMarket = async ( poolRegistry: PoolRegistry, vTokenAddress: string, vTokenConfig: VTokenConfig, - hre: HardhatRuntimeEnvironment, ): Promise => { const { name, collateralFactor, liquidationThreshold, initialSupply, supplyCap, borrowCap } = vTokenConfig; console.log("Adding a command to register " + name + " to PoolRegistry"); - const receiver = await toAddress(vTokenConfig.vTokenReceiver, hre); + const receiver = await toAddress(vTokenConfig.vTokenReceiver); return { contract: poolRegistry.address, signature: "addMarket((address,uint256,uint256,uint256,address,uint256,uint256))", @@ -260,11 +249,7 @@ const setReduceReservesBlockDelta = async ( }; }; -const addMarkets = async ( - unregisteredVTokens: PoolConfig[], - deploymentConfig: DeploymentConfig, - hre: HardhatRuntimeEnvironment, -) => { +const addMarkets = async (unregisteredVTokens: PoolConfig[], deploymentConfig: DeploymentConfig) => { const poolRegistry = await ethers.getContract("PoolRegistry"); const poolCommands = await Promise.all( unregisteredVTokens.map(async (pool: PoolConfig) => { @@ -276,10 +261,10 @@ const addMarkets = async ( console.log("Adding market " + name + " to pool " + pool.name); return [ - ...(await transferInitialLiquidity(vTokenConfig, deploymentConfig, hre)), + ...(await transferInitialLiquidity(vTokenConfig, deploymentConfig)), ...(await approvePoolRegistry(poolRegistry, vTokenConfig, deploymentConfig)), await setReduceReservesBlockDelta(vToken.address, vTokenConfig), - await addMarket(poolRegistry, vToken.address, vTokenConfig, hre), + await addMarket(poolRegistry, vToken.address, vTokenConfig), ]; }), ); @@ -303,20 +288,15 @@ const hasPermission = async ( targetContract: string, method: string, caller: string, - hre: HardhatRuntimeEnvironment, ): Promise => { - const role = makeRole(hre.network.live, targetContract, method); + const role = makeRole(network.live, targetContract, method); return accessControl.hasRole(role, caller); }; -const configureAccessControls = async ( - deploymentConfig: DeploymentConfig, - hre: HardhatRuntimeEnvironment, -): Promise => { +const configureAccessControls = async (deploymentConfig: DeploymentConfig): Promise => { const { accessControlConfig, preconfiguredAddresses } = deploymentConfig; const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); const accessControlManager = await ethers.getContractAt( "AccessControlManager", @@ -325,9 +305,9 @@ const configureAccessControls = async ( const commands = await Promise.all( accessControlConfig.map(async (entry: AccessControlEntry) => { const { caller, target, method } = entry; - const callerAddress = await toAddress(caller, hre); - const targetAddress = await toAddress(target, hre); - if (await hasPermission(accessControlManager, targetAddress, method, callerAddress, hre)) { + const callerAddress = await toAddress(caller); + const targetAddress = await toAddress(target); + if (await hasPermission(accessControlManager, targetAddress, method, callerAddress)) { return []; } return [ @@ -371,19 +351,19 @@ const executeCommands = async (commands: GovernanceCommand[], hre: HardhatRuntim const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { getNamedAccounts } = hre; const { deployer } = await getNamedAccounts(); - const deploymentConfig = await getConfig(hre.network.name); + const deploymentConfig = await getConfig(hre.getNetworkName()); const { poolConfig, preconfiguredAddresses } = deploymentConfig; - const unregisteredPools = await getUnregisteredPools(poolConfig, hre); - const unregisteredVTokens = await getUnregisteredVTokens(poolConfig, hre); - const unregisteredRewardsDistributors = await getUnregisteredRewardsDistributors(poolConfig, hre); + const unregisteredPools = await getUnregisteredPools(poolConfig); + const unregisteredVTokens = await getUnregisteredVTokens(poolConfig); + const unregisteredRewardsDistributors = await getUnregisteredRewardsDistributors(poolConfig); const owner = preconfiguredAddresses.NormalTimelock || deployer; const commands = [ - ...(await configureAccessControls(deploymentConfig, hre)), - ...(await acceptOwnership("PoolRegistry", owner, hre)), - ...(await addPools(unregisteredPools, owner, hre)), - ...(await addMarkets(unregisteredVTokens, deploymentConfig, hre)), - ...(await configureRewards(unregisteredRewardsDistributors, owner, hre)), + ...(await configureAccessControls(deploymentConfig)), + ...(await acceptOwnership("PoolRegistry", owner)), + ...(await addPools(unregisteredPools, owner)), + ...(await addMarkets(unregisteredVTokens, deploymentConfig)), + ...(await configureRewards(unregisteredRewardsDistributors, owner)), ]; if (hre.network.live) { diff --git a/deploy/014-shortfall-protocolshare.ts b/deploy/014-shortfall-protocolshare.ts index 73b8b59f3..7abbbdee3 100644 --- a/deploy/014-shortfall-protocolshare.ts +++ b/deploy/014-shortfall-protocolshare.ts @@ -15,13 +15,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { preconfiguredAddresses } = await getConfig(hre.network.name); + const { preconfiguredAddresses } = await getConfig(hre.getNetworkName()); const poolRegistry = await ethers.getContract("PoolRegistry"); const deployerSigner = ethers.provider.getSigner(deployer); const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); const proxyAdmin = await ethers.getContract("DefaultProxyAdmin"); const owner = await proxyAdmin.owner(); @@ -29,7 +28,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { "hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol:ProxyAdmin", ); - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); + const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.getNetworkName()); const riskFund = await ethers.getContract("RiskFundV2"); @@ -70,4 +69,11 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { }; func.tags = ["Shortfall", "il"]; +// RiskFund not deployed on these networks +func.skip = async hre => + hre.getNetworkName() === "sepolia" || + hre.getNetworkName() === "opbnbtestnet" || + hre.getNetworkName() === "opbnbmainnet" || + hre.getNetworkName() === "ethereum"; + export default func; diff --git a/deploy/016-deploy-beacon-implementations.ts b/deploy/016-deploy-beacon-implementations.ts deleted file mode 100644 index 36ca1451a..000000000 --- a/deploy/016-deploy-beacon-implementations.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ethers } from "hardhat"; -import { DeployFunction } from "hardhat-deploy/types"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; - -import { getMaxBorrowRateMantissa } from "../helpers/deploymentConfig"; -import { getBlockOrTimestampBasedDeploymentInfo } from "../helpers/deploymentUtils"; - -// This deploy script deploys implementations for Comptroller and/or VToken that should be updated through a VIP afterwards -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployments, getNamedAccounts } = hre; - const { deploy } = deployments; - const { deployer } = await getNamedAccounts(); - - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); - - const poolRegistry = await ethers.getContract("PoolRegistry"); - const maxBorrowRateMantissa = getMaxBorrowRateMantissa(hre.network.name); - - // Comptroller Implementation - await deploy("ComptrollerImpl", { - contract: "Comptroller", - from: deployer, - args: [poolRegistry.address], - log: true, - autoMine: true, - }); - - // VToken Implementation - await deploy("VTokenImpl", { - contract: "VToken", - from: deployer, - args: [isTimeBased, blocksPerYear, maxBorrowRateMantissa], - log: true, - autoMine: true, - }); -}; - -func.tags = ["Implementations"]; - -export default func; diff --git a/deploy/017-update-pool-registry.ts b/deploy/017-update-pool-registry.ts deleted file mode 100644 index e165fd80b..000000000 --- a/deploy/017-update-pool-registry.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DeployFunction } from "hardhat-deploy/types"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; - -import { getConfig } from "../helpers/deploymentConfig"; -import { toAddress } from "../helpers/deploymentUtils"; - -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { deployments, getNamedAccounts } = hre; - const { deploy, catchUnknownSigner } = deployments; - const { deployer } = await getNamedAccounts(); - const { preconfiguredAddresses } = await getConfig(hre.network.name); - const proxyOwnerAddress = await toAddress(preconfiguredAddresses.NormalTimelock || "account:deployer", hre); - const defaultProxyAdmin = await hre.artifacts.readArtifact( - "hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol:ProxyAdmin", - ); - await catchUnknownSigner( - deploy("PoolRegistry", { - from: deployer, - contract: "PoolRegistry", - proxy: { - owner: proxyOwnerAddress, - proxyContract: "OptimizedTransparentUpgradeableProxy", - viaAdminContract: { - name: "DefaultProxyAdmin", - artifact: defaultProxyAdmin, - }, - }, - autoMine: true, - log: true, - }), - ); -}; - -func.tags = ["update-pool-registry"]; -export default func; diff --git a/deploy/018-native-token-gateway.ts b/deploy/018-native-token-gateway.ts index e22b143f4..b56570ff2 100644 --- a/deploy/018-native-token-gateway.ts +++ b/deploy/018-native-token-gateway.ts @@ -118,9 +118,9 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { preconfiguredAddresses } = await getConfig(hre.network.name); + const { preconfiguredAddresses } = await getConfig(hre.getNetworkName()); - const vWNativesInfo = getVWNativeTokens(hre.network.name); + const vWNativesInfo = getVWNativeTokens(hre.getNetworkName()); for (const vWNativeInfo of vWNativesInfo) { await deploy(`NativeTokenGateway_${vWNativeInfo.name}`, { contract: "NativeTokenGateway", @@ -133,7 +133,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const nativeTokenGateway = await ethers.getContract(`NativeTokenGateway_${vWNativeInfo.name}`); const targetOwner = preconfiguredAddresses.NormalTimelock || deployer; - if (hre.network.live) { + if (hre.network.live && (await nativeTokenGateway.owner()) !== targetOwner) { const tx = await nativeTokenGateway.transferOwnership(targetOwner); await tx.wait(); console.log(`Transferred ownership of NativeTokenGateway_${vWNativeInfo.name} to Timelock`); diff --git a/deploy/019-deploy-ir-models.ts b/deploy/019-deploy-ir-models.ts index 112df5984..727916509 100644 --- a/deploy/019-deploy-ir-models.ts +++ b/deploy/019-deploy-ir-models.ts @@ -15,13 +15,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deploy } = deployments; const { deployer } = await getNamedAccounts(); - const { poolConfig, preconfiguredAddresses } = await getConfig(hre.network.name); + const { poolConfig, preconfiguredAddresses } = await getConfig(hre.getNetworkName()); - const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.network.name); + const { isTimeBased, blocksPerYear } = getBlockOrTimestampBasedDeploymentInfo(hre.getNetworkName()); const accessControlManagerAddress = await toAddress( preconfiguredAddresses.AccessControlManager || "AccessControlManager", - hre, ); for (const pool of poolConfig) { @@ -32,7 +31,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { if (rateModel === InterestRateModels.JumpRate.toString()) { const [b, m, j, k] = [baseRatePerYear, multiplierPerYear, jumpMultiplierPerYear, kink_].map(mantissaToBps); const rateModelName = `JumpRateModelV2_base${b}bps_slope${m}bps_jump${j}bps_kink${k}bps`; - console.log(`Deploying interest rate model ${rateModelName}`); await deploy(rateModelName, { from: deployer, contract: "JumpRateModelV2", @@ -52,7 +50,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } else { const [b, m] = [baseRatePerYear, multiplierPerYear].map(mantissaToBps); const rateModelName = `WhitePaperInterestRateModel_base${b}bps_slope${m}bps`; - console.log(`Deploying interest rate model ${rateModelName}`); await deploy(rateModelName, { from: deployer, contract: "WhitePaperInterestRateModel", diff --git a/hardhat.config.ts b/hardhat.config.ts index 011e59c8f..3239cd683 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -11,7 +11,7 @@ import "hardhat-dependency-compiler"; import "hardhat-deploy"; import { DeployResult } from "hardhat-deploy/types"; import "hardhat-gas-reporter"; -import { HardhatUserConfig, extendConfig, task, types } from "hardhat/config"; +import { HardhatUserConfig, extendConfig, extendEnvironment, task, types } from "hardhat/config"; import { HardhatConfig } from "hardhat/types"; import "solidity-coverage"; import "solidity-docgen"; @@ -21,46 +21,81 @@ import { convertToUnit } from "./helpers/utils"; dotenv.config(); const DEPLOYER_PRIVATE_KEY = process.env.DEPLOYER_PRIVATE_KEY; +const getRpcUrl = (networkName: string): string => { + let uri; + if (networkName) { + uri = process.env[`ARCHIVE_NODE_${networkName}`]; + } + if (!uri) { + throw new Error(`invalid uri or network not supported by node provider : ${uri}`); + } + return uri; +}; + +extendEnvironment(hre => { + hre.getNetworkName = () => process.env.HARDHAT_FORK_NETWORK || hre.network.name; +}); + extendConfig((config: HardhatConfig) => { if (process.env.EXPORT !== "true") { config.external = { ...config.external, deployments: { + hardhat: [], bsctestnet: [ "node_modules/@venusprotocol/oracle/deployments/bsctestnet", "node_modules/@venusprotocol/venus-protocol/deployments/bsctestnet", "node_modules/@venusprotocol/protocol-reserve/deployments/bsctestnet", + "node_modules/@venusprotocol/governance-contracts/deployments/bsctestnet", ], sepolia: [ "node_modules/@venusprotocol/oracle/deployments/sepolia", "node_modules/@venusprotocol/venus-protocol/deployments/sepolia", "node_modules/@venusprotocol/protocol-reserve/deployments/sepolia", + "node_modules/@venusprotocol/governance-contracts/deployments/sepolia", ], ethereum: [ "node_modules/@venusprotocol/oracle/deployments/ethereum", "node_modules/@venusprotocol/venus-protocol/deployments/ethereum", "node_modules/@venusprotocol/protocol-reserve/deployments/ethereum", + "node_modules/@venusprotocol/governance-contracts/deployments/ethereum", ], bscmainnet: [ "node_modules/@venusprotocol/oracle/deployments/bscmainnet", "node_modules/@venusprotocol/venus-protocol/deployments/bscmainnet", "node_modules/@venusprotocol/protocol-reserve/deployments/bscmainnet", + "node_modules/@venusprotocol/governance-contracts/deployments/bscmainnet", ], opbnbmainnet: [ "node_modules/@venusprotocol/oracle/deployments/opbnbmainnet", "node_modules/@venusprotocol/protocol-reserve/deployments/opbnbmainnet", + "node_modules/@venusprotocol/governance-contracts/deployments/opbnbmainnet", ], opbnbtestnet: [ "node_modules/@venusprotocol/oracle/deployments/opbnbtestnet", "node_modules/@venusprotocol/protocol-reserve/deployments/opbnbtestnet", + "node_modules/@venusprotocol/governance-contracts/deployments/opbnbtestnet", ], arbitrumsepolia: [ "node_modules/@venusprotocol/oracle/deployments/arbitrumsepolia", "node_modules/@venusprotocol/protocol-reserve/deployments/arbitrumsepolia", + "node_modules/@venusprotocol/governance-contracts/deployments/arbitrumsepolia", + ], + arbitrumone: [ + "node_modules/@venusprotocol/protocol-reserve/deployments/arbitrumone", + "node_modules/@venusprotocol/governance-contracts/deployments/arbitrumsepolia", ], - arbitrumone: ["node_modules/@venusprotocol/protocol-reserve/deployments/arbitrumone"], }, }; + if (process.env.HARDHAT_FORK_NETWORK) { + config.external.deployments!.hardhat = [ + `./deployments/${process.env.HARDHAT_FORK_NETWORK}`, + `node_modules/@venusprotocol/oracle/deployments/${process.env.HARDHAT_FORK_NETWORK}`, + `node_modules/@venusprotocol/venus-protocol/deployments/${process.env.HARDHAT_FORK_NETWORK}`, + `node_modules/@venusprotocol/protocol-reserve/deployments/${process.env.HARDHAT_FORK_NETWORK}`, + `node_modules/@venusprotocol/governance-contracts/deployments/${process.env.HARDHAT_FORK_NETWORK}`, + ]; + } } }); @@ -217,7 +252,13 @@ const config: HardhatUserConfig = { hardhat: { allowUnlimitedContractSize: true, loggingEnabled: false, - live: false, + live: !!process.env.HARDHAT_FORK_NETWORK, + forking: process.env.HARDHAT_FORK_NETWORK + ? { + url: getRpcUrl(process.env.HARDHAT_FORK_NETWORK), + blockNumber: process.env.HARDHAT_FORK_NUMBER ? parseInt(process.env.HARDHAT_FORK_NUMBER) : undefined, + } + : undefined, }, development: { url: "http://127.0.0.1:8545/", diff --git a/helpers/deploymentConfig.ts b/helpers/deploymentConfig.ts index 02c6670d9..75693a8eb 100644 --- a/helpers/deploymentConfig.ts +++ b/helpers/deploymentConfig.ts @@ -3807,7 +3807,7 @@ export const globalConfig: NetworkConfig = { // 3600 XVS for Borrowers { asset: "XVS", - markets: ["vCRV", "crvUSD"], + markets: ["CRV", "crvUSD"], supplySpeeds: ["925925925925925", "3703703703703703"], borrowSpeeds: ["1388888888888888", "5555555555555555"], }, @@ -3819,7 +3819,7 @@ export const globalConfig: NetworkConfig = { }, { asset: "XVS", - markets: ["vCRV", "crvUSD"], + markets: ["CRV", "crvUSD"], supplySpeeds: ["694444444444444", "694444444444444"], borrowSpeeds: ["1041666666666666", "1041666666666666"], }, diff --git a/helpers/deploymentUtils.ts b/helpers/deploymentUtils.ts index acdfcfc0c..e578f25d6 100644 --- a/helpers/deploymentUtils.ts +++ b/helpers/deploymentUtils.ts @@ -1,5 +1,4 @@ -import { ethers } from "hardhat"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { deployments, ethers, getNamedAccounts } from "hardhat"; import { Comptroller, ERC20, MockToken } from "../typechain"; import { @@ -12,9 +11,7 @@ import { getTokenConfig, } from "./deploymentConfig"; -export const toAddress = async (addressOrAlias: string, hre: HardhatRuntimeEnvironment): Promise => { - const { getNamedAccounts } = hre; - const { deployments } = hre; +export const toAddress = async (addressOrAlias: string): Promise => { if (addressOrAlias.startsWith("0x")) { return addressOrAlias; } @@ -39,11 +36,7 @@ export const getUnderlyingToken = async (assetSymbol: string, tokensConfig: Toke return ethers.getContractAt("@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20", underlyingAddress); }; -export const getUnregisteredPools = async ( - poolConfig: PoolConfig[], - hre: HardhatRuntimeEnvironment, -): Promise => { - const { deployments } = hre; +export const getUnregisteredPools = async (poolConfig: PoolConfig[]): Promise => { const registry = await ethers.getContract("PoolRegistry"); const registeredPools = (await registry.getAllPools()).map((p: { comptroller: string }) => p.comptroller); const isRegistered = await Promise.all( @@ -59,11 +52,7 @@ export const getUnregisteredPools = async ( return poolConfig.filter((_, idx: number) => !isRegistered[idx]); }; -export const getUnregisteredVTokens = async ( - poolConfig: PoolConfig[], - hre: HardhatRuntimeEnvironment, -): Promise => { - const { deployments } = hre; +export const getUnregisteredVTokens = async (poolConfig: PoolConfig[]): Promise => { const registry = await ethers.getContract("PoolRegistry"); const registeredPools = await registry.getAllPools(); const comptrollers = await Promise.all( @@ -96,11 +85,7 @@ export const getUnregisteredVTokens = async ( ); }; -export const getUnregisteredRewardsDistributors = async ( - poolConfig: PoolConfig[], - hre: HardhatRuntimeEnvironment, -): Promise => { - const { deployments } = hre; +export const getUnregisteredRewardsDistributors = async (poolConfig: PoolConfig[]): Promise => { const registry = await ethers.getContract("PoolRegistry"); const registeredPools = await registry.getAllPools(); const comptrollers = await Promise.all( diff --git a/tsconfig.json b/tsconfig.json index 3f95231ec..979599aeb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,6 @@ "@nomiclabs/hardhat-ethers": ["./node_modules/hardhat-deploy-ethers"] } }, - "include": ["./typechain", "./deploy", "./helpers"], + "include": ["./typechain", "./deploy", "./helpers", "./type-extensions.ts"], "files": ["./hardhat.config.ts"] } diff --git a/type-extensions.ts b/type-extensions.ts new file mode 100644 index 000000000..2fae4ac31 --- /dev/null +++ b/type-extensions.ts @@ -0,0 +1,9 @@ +import "hardhat/types/runtime"; + +declare module "hardhat/types/runtime" { + // This is an example of an extension to the Hardhat Runtime Environment. + // This new field will be available in tasks' actions, scripts, and tests. + export interface HardhatRuntimeEnvironment { + getNetworkName: () => string; + } +}