Skip to content

Commit

Permalink
Sepolia cWETHv3 deploy and proposal (#832)
Browse files Browse the repository at this point in the history
Deploys cWETHv3 to Sepolia and initializes it with a proposal.
  • Loading branch information
kevincheng96 authored Mar 3, 2024
1 parent 745fddd commit 55960cd
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-scenarios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: false
matrix:
bases: [ development, mainnet, mainnet-weth, goerli, goerli-weth, sepolia-usdc, fuji, mumbai, polygon, arbitrum-usdc.e, arbitrum-usdc, arbitrum-goerli-usdc, arbitrum-goerli-usdc.e, base-usdbc, base-weth, base-goerli, base-goerli-weth, linea-goerli]
bases: [ development, mainnet, mainnet-weth, goerli, goerli-weth, sepolia-usdc, sepolia-weth, fuji, mumbai, polygon, arbitrum-usdc.e, arbitrum-usdc, arbitrum-goerli-usdc, arbitrum-goerli-usdc.e, base-usdbc, base-weth, base-goerli, base-goerli-weth, linea-goerli]
name: Run scenarios
env:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion MIGRATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ After preparation, a migration stores some artifacts under `deployments/goerli/u

Migrations can be tested using Comet's [scenario framework](https://github.com/compound-finance/comet/blob/main/SCENARIO.md).

Migrations that have been committed to a branch but not enacted yet will automatically be picked up and run by the scenarios framework (in the [MigrationConstraint](https://github.com/compound-finance/comet/blob/main/scenario/constraints/MigrationConstraint.ts)). This ensures that any new migrations are checked against all existing scenarios and any issues with a migration can be proactively caught.
Migrations that have been staged to a branch but not enacted yet will automatically be picked up and run by the scenarios framework (in the [MigrationConstraint](https://github.com/compound-finance/comet/blob/main/scenario/constraints/MigrationConstraint.ts)). This ensures that any new migrations are checked against all existing scenarios and any issues with a migration can be proactively caught. Remember, migrations **need to be staged in git** before it can be picked up by scenarios.

Migrations should also include a `verify` function to check that the correct state-changes are made by it. This `verify` block is also run as part of the scenario framework.

Expand Down
44 changes: 44 additions & 0 deletions deployments/sepolia/weth/configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "Compound WETH",
"symbol": "cWETHv3",
"baseToken": "WETH",
"baseTokenAddress": "0x2D5ee574e710219a521449679A4A7f2B43f046ad",
"borrowMin": "1e12",
"governor": "0x54a06047087927D9B0fb21c1cf0ebd792764dDB8",
"pauseGuardian": "0x008a4C5448ac1Df676d6F39A0C6F13b21b189389",
"storeFrontPriceFactor": 0.5,
"targetReserves": "5000e18",
"rates": {
"supplyKink": 0.9,
"supplySlopeLow": 0.01690681444,
"supplySlopeHigh": 0.6066567706,
"supplyBase": 0,
"borrowKink": 0.9,
"borrowSlopeLow": 0.05171500002,
"borrowSlopeHigh": 0.5171500339,
"borrowBase": 0.009945209674
},
"tracking": {
"indexScale": "1e15",
"baseSupplySpeed": "0.000011574074074074073e15",
"baseBorrowSpeed": "0e15",
"baseMinForRewards": "0.1e18"
},
"assets": {
"cbETH": {
"decimals": "18",
"borrowCF": 0.90,
"liquidateCF": 0.93,
"liquidationFactor": 0.95,
"supplyCap": "9_000e18"
},
"wstETH": {
"address": "0xB82381A3fBD3FaFA77B3a7bE693342618240067b",
"decimals": "18",
"borrowCF": 0.90,
"liquidateCF": 0.93,
"liquidationFactor": 0.95,
"supplyCap": "80_000e18"
}
}
}
147 changes: 147 additions & 0 deletions deployments/sepolia/weth/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager';
import { debug, DeploySpec, deployComet, exp, sameAddress, wait } from '../../../src/deploy';

const clone = {
cbETHImpl: '0x31724cA0C982A31fbb5C57f4217AB585271fc9a5',
cbETHProxy: '0xBe9895146f7AF43049ca1c1AE358B0541Ea49704',
};

export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise<Deployed> {
const deployed = await deployContracts(deploymentManager, deploySpec);
await mintTokens(deploymentManager);
return deployed;
}

async function deployContracts(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise<Deployed> {
const ethers = deploymentManager.hre.ethers;
const signer = await deploymentManager.getSigner();

// Declare existing assets as aliases
const WETH = await deploymentManager.existing('WETH', '0x2D5ee574e710219a521449679A4A7f2B43f046ad', 'sepolia');
const wstETH = await deploymentManager.existing('wstETH', '0xB82381A3fBD3FaFA77B3a7bE693342618240067b', 'sepolia');

// Import shared contracts from cUSDCv3
const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'sepolia', 'usdc');
const cometFactory = await deploymentManager.fromDep('cometFactory', 'sepolia', 'usdc');
const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'sepolia', 'usdc');
const configurator = await deploymentManager.fromDep('configurator', 'sepolia', 'usdc');
const rewards = await deploymentManager.fromDep('rewards', 'sepolia', 'usdc');
const fauceteer = await deploymentManager.fromDep('fauceteer', 'sepolia', 'usdc');

// Clone cbETH
const cbETHProxyAdmin = await deploymentManager.deploy('cbETH:admin', 'vendor/proxy/transparent/ProxyAdmin.sol', []);
const cbETHImpl = await deploymentManager.clone('cbETH:implementation', clone.cbETHImpl, []);
const cbETHProxy = await deploymentManager.clone('cbETH', clone.cbETHProxy, [cbETHImpl.address]);
const cbETHProxyAdminSlot = '0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b';
const cbETH = cbETHImpl.attach(cbETHProxy.address);
await deploymentManager.idempotent(
async () => !sameAddress(await ethers.provider.getStorageAt(cbETHProxy.address, cbETHProxyAdminSlot), cbETHProxyAdmin.address),
async () => {
debug(`Changing admin of cbETH proxy to ${cbETHProxyAdmin.address}`);
await wait(cbETHProxy.connect(signer).changeAdmin(cbETHProxyAdmin.address));

debug(`Initializing cbETH`);
await wait(cbETH.connect(signer).initialize(
'Coinbase Wrapped Staked ETH', // name
'cbETH', // symbol
'', // currency
18, // decimals
signer.address, // Master Minter
signer.address, // Pauser
signer.address, // Blacklister
signer.address // Owner
));
}
);

// Deploy stETH / ETH SimplePriceFeed
const stETHtoETHPriceFeed = await deploymentManager.deploy(
'stETHToETH:simplePriceFeed',
'test/SimplePriceFeed.sol',
[
exp(0.98882408, 18), // Latest answer on mainnet at block 16170924
18
]
);

// Deploy cbETH / ETH SimplePriceFeed
const cbETHtoETHPriceFeed = await deploymentManager.deploy(
'cbETHToETH:simplePriceFeed',
'test/SimplePriceFeed.sol',
[
exp(0.97, 18),
18
]
);

// Deploy WstETHPriceFeed
const wstETHPriceFeed = await deploymentManager.deploy(
'wstETH:priceFeed',
'pricefeeds/WstETHPriceFeed.sol',
[
stETHtoETHPriceFeed.address, // stETH / ETH price feed
wstETH.address, // wstETH
8 // decimals
]
);

// Deploy constant price feed for WETH
const wethConstantPriceFeed = await deploymentManager.deploy(
'WETH:priceFeed',
'pricefeeds/ConstantPriceFeed.sol',
[
8, // decimals
exp(1, 8) // constantPrice
]
);

// Deploy scaling price feed for cbETH
const cbETHScalingPriceFeed = await deploymentManager.deploy(
'cbETH:priceFeed',
'pricefeeds/ScalingPriceFeed.sol',
[
cbETHtoETHPriceFeed.address, // cbETH / ETH price feed
8 // decimals
]
);

// Deploy all Comet-related contracts
const deployed = await deployComet(deploymentManager, deploySpec);
const { comet } = deployed;

// Deploy Bulker
const bulker = await deploymentManager.deploy(
'bulker',
'bulkers/MainnetBulker.sol',
[
await comet.governor(), // admin_
WETH.address, // weth_
wstETH.address // wsteth_
]
);

return { ...deployed, bulker, fauceteer };
}

async function mintTokens(deploymentManager: DeploymentManager) {
const signer = await deploymentManager.getSigner();
const contracts = await deploymentManager.contracts();
const fauceteer = contracts.get('fauceteer')!;

debug(`Attempting to mint as ${signer.address}...`);

// If we haven't spidered new contracts (which we could before minting, but its slow),
// then the proxy contract won't have the impl functions yet, so just do it explicitly
const cbETHProxy = contracts.get('cbETH')!, cbETHImpl = contracts.get('cbETH:implementation')!;
const cbETH = cbETHImpl.attach(cbETHProxy.address);
await deploymentManager.idempotent(
async () => (await cbETH.balanceOf(fauceteer.address)).eq(0),
async () => {
debug(`Minting 1M cbETH to fauceteer`);
const amount = exp(1_000_000, await cbETH.decimals());
await wait(cbETH.connect(signer).configureMinter(signer.address, amount));
await wait(cbETH.connect(signer).mint(fauceteer.address, amount));
debug(`cbETH.balanceOf(${fauceteer.address}): ${await cbETH.balanceOf(fauceteer.address)}`);
}
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { DeploymentManager, migration } from '../../../../plugins/deployment_manager';
import { exp, getConfigurationStruct, proposal } from '../../../../src/deploy';

import { expect } from 'chai';

const COMPAddress = '0xA6c8D1c55951e8AC44a0EaA959Be5Fd21cc07531';

export default migration('1709094543_initialize_market', {
prepare: async (deploymentManager: DeploymentManager) => {
return {};
},

enact: async (deploymentManager: DeploymentManager) => {
const trace = deploymentManager.tracer();

// Import shared contracts from cUSDCv3
const cometFactory = await deploymentManager.fromDep('cometFactory', 'sepolia', 'usdc');

const {
governor,
comet,
configurator,
cometAdmin,
rewards,
} = await deploymentManager.getContracts();

const configuration = await getConfigurationStruct(deploymentManager);

const actions = [
// 1. Set the factory in the Configurator
{
contract: configurator,
signature: 'setFactory(address,address)',
args: [comet.address, cometFactory.address],
},

// 2. Set the configuration in the Configurator
{
contract: configurator,
signature: 'setConfiguration(address,(address,address,address,address,address,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint64,uint104,uint104,uint104,(address,address,uint8,uint64,uint64,uint64,uint128)[]))',
args: [comet.address, configuration],
},

// 3. Deploy and upgrade to a new version of Comet
{
contract: cometAdmin,
signature: "deployAndUpgradeTo(address,address)",
args: [configurator.address, comet.address],
},

// 4. Set the rewards configuration to COMP
{
contract: rewards,
signature: "setRewardConfig(address,address)",
args: [comet.address, COMPAddress],
},
];
const description = "# Initialize cWETHv3 on Sepolia"
const txn = await deploymentManager.retry(
async () => trace((await governor.propose(...await proposal(actions, description))))
);

const event = txn.events.find(event => event.event === 'ProposalCreated');
const [proposalId] = event.args;

trace(`Created proposal ${proposalId}.`);
},

async enacted(deploymentManager: DeploymentManager): Promise<boolean> {
return true;
},

async verify(deploymentManager: DeploymentManager) {
const {
comet,
rewards,
wstETH,
cbETH,
} = await deploymentManager.getContracts();
// 2. & 3.
expect(await comet.baseTrackingSupplySpeed()).to.be.equal(exp(1 / 86400, 15, 18)); // ~ 1 COMP / day
expect(await comet.baseTrackingBorrowSpeed()).to.be.equal(0);

const wstETHInfo = await comet.getAssetInfoByAddress(wstETH.address);
expect(wstETHInfo.supplyCap).to.be.equal(exp(80_000, 18)); // ~ $100M / $1225

const cbETHInfo = await comet.getAssetInfoByAddress(cbETH.address);
expect(cbETHInfo.supplyCap).to.be.equal(exp(9_000, 18)); // ~ $10M / $1091

// 4.
const config = await rewards.rewardConfig(comet.address);
expect(config.token).to.be.equal(COMPAddress);
expect(config.rescaleFactor).to.be.equal(1000000000000n);
expect(config.shouldUpscale).to.be.equal(true);
},
});
13 changes: 13 additions & 0 deletions deployments/sepolia/weth/relations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import baseRelationConfig from '../../relations';

export default {
...baseRelationConfig,
'wstETH': {
artifact: 'contracts/bulkers/IWstETH.sol',
relations: {
stETH: {
field: async (wstETH) => wstETH.stETH()
}
}
},
};
7 changes: 7 additions & 0 deletions deployments/sepolia/weth/roots.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"comet": "0x2943ac1216979aD8dB76D9147F64E61adc126e96",
"configurator": "0xc28aD44975C614EaBe0Ed090207314549e1c6624",
"rewards": "0x8bF5b658bdF0388E8b482ED51B14aef58f90abfD",
"bulker": "0xaD0C044425D81a2E223f4CE699156900fead2Aaa",
"fauceteer": "0x68793eA49297eB75DFB4610B68e076D2A5c7646C"
}
9 changes: 8 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import relationConfigMap from './deployments/relations';
import goerliRelationConfigMap from './deployments/goerli/usdc/relations';
import goerliWethRelationConfigMap from './deployments/goerli/weth/relations';
import sepoliaUsdcRelationConfigMap from './deployments/sepolia/usdc/relations';
import sepoliaWethRelationConfigMap from './deployments/sepolia/weth/relations';
import mumbaiRelationConfigMap from './deployments/mumbai/usdc/relations';
import mainnetRelationConfigMap from './deployments/mainnet/usdc/relations';
import mainnetWethRelationConfigMap from './deployments/mainnet/weth/relations';
Expand Down Expand Up @@ -295,7 +296,8 @@ const config: HardhatUserConfig = {
weth: goerliWethRelationConfigMap
},
sepolia: {
usdc: sepoliaUsdcRelationConfigMap
usdc: sepoliaUsdcRelationConfigMap,
weth: sepoliaWethRelationConfigMap
},
mumbai: {
usdc: mumbaiRelationConfigMap
Expand Down Expand Up @@ -367,6 +369,11 @@ const config: HardhatUserConfig = {
network: 'sepolia',
deployment: 'usdc'
},
{
name: 'sepolia-weth',
network: 'sepolia',
deployment: 'weth'
},
{
name: 'mumbai',
network: 'mumbai',
Expand Down

0 comments on commit 55960cd

Please sign in to comment.