Skip to content

Commit

Permalink
Merge pull request #442 from VenusProtocol/add-forked-deployment
Browse files Browse the repository at this point in the history
Add forked deployment
  • Loading branch information
coreyar authored Dec 26, 2024
2 parents 01239a9 + 6d0ad6c commit 0491b86
Show file tree
Hide file tree
Showing 24 changed files with 195 additions and 231 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ ETHERSCAN_API_KEY=
REPORT_GAS=

# Set to true or false to deploy contracts based on timestamp or block
IS_TIME_BASED_DEPLOYMENT=false
IS_TIME_BASED_DEPLOYMENT=false
HARDHAT_FORK_NETWORK=
2 changes: 1 addition & 1 deletion .eslint-tsconfig
Original file line number Diff line number Diff line change
@@ -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"]
}
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ npx hardhat deploy
- In the deployment scripts you have added `tags` for example: - `func.tags = ["MockTokens"];`
- Once this is done, adding `--tags "<tag_name>,<tag_name>..."` 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
Expand Down
6 changes: 4 additions & 2 deletions deploy/001-deploy-mock-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -27,4 +27,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

func.tags = ["MockTokens"];

func.skip = async hre => hre.network.live;

export default func;
14 changes: 7 additions & 7 deletions deploy/004-swap-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
5 changes: 2 additions & 3 deletions deploy/006-deploy-pool-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion deploy/007-deploy-pool-lens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 3 additions & 5 deletions deploy/008-deploy-comptrollers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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",
Expand Down
8 changes: 2 additions & 6 deletions deploy/009-deploy-vtokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,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);
await timelocksDeployment(hre);
const accessControlManagerAddress = await toAddress(
preconfiguredAddresses.AccessControlManager || "AccessControlManager",
hre,
);

// VToken Beacon
Expand All @@ -49,7 +48,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}`);

Expand Down Expand Up @@ -82,7 +81,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",
Expand All @@ -103,7 +101,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",
Expand All @@ -115,7 +112,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;
Expand Down
13 changes: 5 additions & 8 deletions deploy/010-deploy-reward-distributors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
28 changes: 13 additions & 15 deletions deploy/011-initial-liquidity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BigNumber } from "ethers";
import { getNetworkName } from "hardhat";
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

Expand All @@ -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))
Expand All @@ -42,38 +43,35 @@ 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),
}));
const totalAmounts = await sumAmounts(amounts);
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);
}
};

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"];
Expand Down
46 changes: 23 additions & 23 deletions deploy/012-transfer-pools-ownership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down Expand Up @@ -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;
Loading

0 comments on commit 0491b86

Please sign in to comment.