Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update base price feed for cWstETHv3 on Mainnet #933

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
51e63e5
feat: new pricefeeds
MishaShWoof Jul 1, 2024
2c33985
fix: rename
MishaShWoof Jul 1, 2024
cd5236c
feat: add migration
MishaShWoof Jul 1, 2024
0807aea
fix: fix migration
MishaShWoof Jul 1, 2024
5e4bd91
fix: add description
MishaShWoof Jul 2, 2024
f242649
fix: post audit fixes
MishaShWoof Jul 8, 2024
563f2ba
fix: add sanity checks
MishaShWoof Jul 8, 2024
ada2986
feat: add force deploy, because rsETH and weETH already exist, but we…
dmitriy-woof-software Jul 13, 2024
4f72982
merge main
dmitriy-woof-software Jul 13, 2024
5974cff
feat: add ezETH part as it was queued, but not executed; it will allo…
dmitriy-woof-software Jul 13, 2024
58076fd
Merge branch 'main' of github.com:woof-software/comet into woof-softw…
MishaShWoof Aug 8, 2024
a79f38c
fix
MishaShWoof Aug 8, 2024
bcb8732
fix: manually set enacted as true
MishaShWoof Aug 8, 2024
abdc3cd
feat: add migration and necessary changes
MishaShWoof Aug 19, 2024
6557117
feat: add description
MishaShWoof Aug 19, 2024
ea6c6db
Merge branch 'main' of github.com:woof-software/comet into woof-softw…
MishaShWoof Aug 23, 2024
4b137fb
fix: change bulker scenario
MishaShWoof Aug 23, 2024
802204c
fix: remove commented code
MishaShWoof Aug 23, 2024
c818da9
fix: clean up
MishaShWoof Aug 23, 2024
cf9cc71
fix: remove weETH from the configuration
MishaShWoof Aug 27, 2024
04d2623
feat: add new workflow and update configs
MishaShWoof Aug 27, 2024
96b8e8d
feat: create new task
MishaShWoof Aug 27, 2024
2db7f1c
fix
MishaShWoof Aug 28, 2024
98fc0c2
fix: linter
MishaShWoof Aug 28, 2024
ca245ce
fix: fixes for contract after audit
MishaShWoof Sep 4, 2024
18f9d8c
fix: working migration
MishaShWoof Sep 4, 2024
8f70ce0
fix: description, rewards and scenario fixes
MishaShWoof Sep 4, 2024
f7b6607
fix: reduce seeded reserves to 20
MishaShWoof Sep 4, 2024
5500d7b
Modified deployment roots from GitHub Actions
Sep 5, 2024
7481cd3
feat: set caps and speeds
MishaShWoof Sep 5, 2024
9c6025e
fix: revert skip
MishaShWoof Sep 9, 2024
001a437
Modified migration from GitHub Actions
Sep 9, 2024
801f595
feat: migration to update price feed
MishaShWoof Sep 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions .github/workflows/enact-migration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ on:
description: Impersonate Account
required: false
default: ''
with_deploy:
type: boolean
description: Deploy Market
required: false
default: false
jobs:
enact-migration:
name: Enact Migration
Expand Down Expand Up @@ -108,6 +113,17 @@ jobs:
path: deployments/${{ github.event.inputs.network }}/${{ github.event.inputs.deployment }}/artifacts/
if: github.event.inputs.run_id != ''

- name: Run Deploy Market and Enact Migration (impersonate)
run: |
yarn hardhat deploy_and_migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }}
env:
DEBUG: true
ETH_PK: "${{ inputs.eth_pk }}"
NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }}
GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }}
GOV_NETWORK: ${{ env.GOV_NETWORK }}
REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }}
if: github.event.inputs.impersonateAccount != '' && github.event.inputs.with_deploy == 'true'
- name: Run Enact Migration
run: |
yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }}
Expand All @@ -118,7 +134,7 @@ jobs:
GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }}
GOV_NETWORK: ${{ env.GOV_NETWORK }}
REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }}
if: github.event.inputs.impersonateAccount == ''
if: github.event.inputs.impersonateAccount == '' && github.event.inputs.with_deploy == 'false'
- name: Run Enact Migration (impersonate)
run: |
yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }}
Expand All @@ -129,7 +145,7 @@ jobs:
GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }}
GOV_NETWORK: ${{ env.GOV_NETWORK }}
REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }}
if: github.event.inputs.impersonateAccount != ''
if: github.event.inputs.impersonateAccount != '' && github.event.inputs.with_deploy == 'false'
- name: Commit changes
if: ${{ github.event.inputs.simulate == 'false' }}
run: |
Expand Down
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, mainnet-usdt, goerli, goerli-weth, sepolia-usdc, sepolia-weth, fuji, mumbai, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, arbitrum-goerli-usdc, arbitrum-goerli-usdc.e, base-usdbc, base-weth, base-usdc, base-goerli, base-goerli-weth, linea-goerli, optimism-usdc, optimism-usdt, optimism-weth, scroll-goerli, scroll-usdc]
bases: [ development, mainnet, mainnet-weth, mainnet-usdt, mainnet-wsteth, goerli, goerli-weth, sepolia-usdc, sepolia-weth, fuji, mumbai, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, arbitrum-goerli-usdc, arbitrum-goerli-usdc.e, base-usdbc, base-weth, base-usdc, base-goerli, base-goerli-weth, linea-goerli, optimism-usdc, optimism-usdt, optimism-weth, scroll-goerli, scroll-usdc]
name: Run scenarios
env:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
Expand Down
109 changes: 109 additions & 0 deletions contracts/bulkers/MainnetBulkerWithWstETHSupport.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./BaseBulker.sol";
import "../IWstETH.sol";

/**
* @title Compound's Bulker contract for Ethereum mainnet
* @notice Executes multiple Comet-related actions in a single transaction
* @author Compound
*/
contract MainnetBulkerWithWstETHSupport is BaseBulker {
/** General configuration constants **/

/// @notice The address of Lido staked ETH
address public immutable steth;

/// @notice The address of Lido wrapped staked ETH
address public immutable wsteth;

/** Actions **/

/// @notice The action for supplying staked ETH to Comet
bytes32 public constant ACTION_SUPPLY_STETH = "ACTION_SUPPLY_STETH";

/// @notice The action for withdrawing staked ETH from Comet
bytes32 public constant ACTION_WITHDRAW_STETH = "ACTION_WITHDRAW_STETH";

/** Custom errors **/

error UnsupportedBaseAsset();

/**
* @notice Construct a new MainnetBulker instance
* @param admin_ The admin of the Bulker contract
* @param weth_ The address of wrapped ETH
* @param wsteth_ The address of Lido wrapped staked ETH
**/
constructor(
address admin_,
address payable weth_,
address wsteth_
) BaseBulker(admin_, weth_) {
wsteth = wsteth_;
steth = IWstETH(wsteth_).stETH();
}

/**
* @notice Handles actions specific to the Ethereum mainnet version of Bulker, specifically supplying and withdrawing stETH
*/
function handleAction(bytes32 action, bytes calldata data) override internal {
if (action == ACTION_SUPPLY_STETH) {
(address comet, address to, uint stETHAmount) = abi.decode(data, (address, address, uint));
supplyStEthTo(comet, to, stETHAmount);
} else if (action == ACTION_WITHDRAW_STETH) {
(address comet, address to, uint wstETHAmount) = abi.decode(data, (address, address, uint));
withdrawStEthTo(comet, to, wstETHAmount);
} else {
revert UnhandledAction();
}
}

/**
* @notice Wraps stETH to wstETH and supplies to a user in Comet
* @dev Note: This contract must have permission to manage msg.sender's Comet account
* @dev Note: Supports `stETHAmount` of `uint256.max` to fully repay the wstETH debt
* @dev Note: Only for the cwstETHv3 market
*/
function supplyStEthTo(address comet, address to, uint stETHAmount) internal {
if(CometInterface(comet).baseToken() != wsteth) revert UnsupportedBaseAsset();
uint256 _stETHAmount = stETHAmount == type(uint256).max
? IWstETH(wsteth).getStETHByWstETH(CometInterface(comet).borrowBalanceOf(msg.sender))
: stETHAmount;
doTransferIn(steth, msg.sender, _stETHAmount);
ERC20(steth).approve(wsteth, _stETHAmount);
uint wstETHAmount = IWstETH(wsteth).wrap(_stETHAmount);
ERC20(wsteth).approve(comet, wstETHAmount);
CometInterface(comet).supplyFrom(address(this), to, wsteth, wstETHAmount);
}

/**
* @notice Withdraws wstETH from Comet, unwraps it to stETH, and transfers it to a user
* @dev Note: This contract must have permission to manage msg.sender's Comet account
* @dev Note: Supports `amount` of `uint256.max` to withdraw all wstETH from Comet
* @dev Note: Only for the cwstETHv3 market
*/
function withdrawStEthTo(address comet, address to, uint stETHAmount) internal {
if(CometInterface(comet).baseToken() != wsteth) revert UnsupportedBaseAsset();
uint wstETHAmount = stETHAmount == type(uint256).max
? CometInterface(comet).balanceOf(msg.sender)
: IWstETH(wsteth).getWstETHByStETH(stETHAmount);
CometInterface(comet).withdrawFrom(msg.sender, address(this), wsteth, wstETHAmount);
uint unwrappedStETHAmount = IWstETH(wsteth).unwrap(wstETHAmount);
doTransferOut(steth, to, unwrappedStETHAmount);
}

/**
* @notice Submits received ether to get stETH and wraps it to wstETH, received wstETH is transferred to Comet
*/
function deposit(address comet) external payable {
if(msg.sender != admin) revert Unauthorized();
if(CometInterface(comet).baseToken() != wsteth) revert UnsupportedBaseAsset();
(bool success, ) = payable(wsteth).call{value: msg.value}(new bytes(0));
if(!success) revert TransferOutFailed();

uint wstETHAmount = ERC20(wsteth).balanceOf(address(this));
doTransferOut(wsteth, comet, wstETHAmount);
}
}
46 changes: 46 additions & 0 deletions deployments/mainnet/wsteth/configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "Compound wstETH",
"symbol": "cWstETHv3",
"baseToken": "wstETH",
"baseTokenAddress": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0",
"borrowMin": "0.1e18",
"governor": "0x6d903f6003cca6255d85cca4d3b5e5146dc33925",
"pauseGuardian": "0xbbf3f1421d886e9b2c5d716b5192ac998af2012c",
"storeFrontPriceFactor": 0.7,
"targetReserves": "5000e18",
"rates": {
"supplyBase": 0,
"supplySlopeLow": 0.012,
"supplyKink": 0.85,
"supplySlopeHigh": 1,
"borrowBase": 0.01,
"borrowSlopeLow": 0.014,
"borrowKink": 0.85,
"borrowSlopeHigh": 1.15
},
"tracking": {
"indexScale": "1e15",
"baseSupplySpeed": "92592592592e0",
"baseBorrowSpeed": "46296296296e0",
"baseMinForRewards": "10e18"
},
"rewardTokenAddress": "0xc00e94cb662c3520282e6f5717214004a7f26888",
"assets": {
"rsETH": {
"address": "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7",
"decimals": "18",
"borrowCF": 0.88,
"liquidateCF": 0.91,
"liquidationFactor": 0.96,
"supplyCap": "10_000e18"
},
"ezETH": {
"address": "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110",
"decimals": "18",
"borrowCF": 0.88,
"liquidateCF": 0.91,
"liquidationFactor": 0.94,
"supplyCap": "15_000e18"
}
}
}
77 changes: 77 additions & 0 deletions deployments/mainnet/wsteth/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager';
import { DeploySpec, deployComet, exp } from '../../../src/deploy';

export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise<Deployed> {
const wstETH = await deploymentManager.existing('wstETH', '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0');
const weth = await deploymentManager.existing('weth', '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2');
const rsETHToETHPriceFeed = await deploymentManager.fromDep('rsETH:priceFeed', 'mainnet', 'weth');
const wstETHToETHPriceFeed = await deploymentManager.fromDep('wstETH:priceFeed', 'mainnet', 'weth');
const ezETHToETHPriceFeed = await deploymentManager.fromDep('ezETH:priceFeed', 'mainnet', 'weth');
const weETHToETHPriceFeed = await deploymentManager.fromDep('weETH:priceFeed', 'mainnet', 'weth');

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

// Deploy reverse multiplicative price feed for rsETH
const rsETHScalingPriceFeed = await deploymentManager.deploy(
'rsETH:priceFeed',
'pricefeeds/ReverseMultiplicativePriceFeed.sol',
[
rsETHToETHPriceFeed.address, // rsETH / ETH price feed
wstETHToETHPriceFeed.address, // wstETH / ETH price feed (reversed)
8, // decimals
'rsETH / wstETH price feed' // description
],
true
);

// Deploy reverse multiplicative price feed for ezETH
const ezETHScalingPriceFeed = await deploymentManager.deploy(
'ezETH:priceFeed',
'pricefeeds/ReverseMultiplicativePriceFeed.sol',
[
ezETHToETHPriceFeed.address, // ezETH / ETH price feed
wstETHToETHPriceFeed.address, // wstETH / ETH price feed (reversed)
8, // decimals
'ezETH / wstETH price feed' // description
],
true
);

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

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

// Deploy Bulker
const bulker = await deploymentManager.deploy(
'bulker',
'bulkers/MainnetBulkerWithWstETHSupport.sol',
[
await comet.governor(), // admin_
weth.address, // weth_
wstETH.address // wsteth_
],
true
);
console.log('Bulker deployed at:', bulker.address);

const bulkerNow = await deploymentManager.contract('bulker');
console.log('Bulker now at:', bulkerNow? bulkerNow.address: 'N/A');

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