From 855456a26c1c0ec9ff0c89a2754f85c62e0443cb Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Sat, 27 Jul 2024 00:53:02 +0300 Subject: [PATCH 1/8] feat: add migration --- ...989723_add_usdt_and_usdc_as_collaterals.ts | 211 ++++++++++++++++++ scenario/constraints/ProposalConstraint.ts | 6 +- 2 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts diff --git a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts new file mode 100644 index 000000000..b34a77868 --- /dev/null +++ b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts @@ -0,0 +1,211 @@ +import { expect } from 'chai'; +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { exp, proposal } from '../../../../src/deploy'; + +const USDT_ADDRESS = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; +const USDT_PRICE_FEED_ADDRESS = '0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46'; + +const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; +const USDC_PRICE_FEED_ADDRESS = '0x986b5E1e1755e3C2440e960477f25201B0a8bbD4'; + +const NEW_FACTORY_ADDRESS = '0x89128FE4Fc91038C13220E74991F9557F816c865'; + +export default migration('1721989723_add_usdt_and_usdc_as_collaterals', { + async prepare(deploymentManager: DeploymentManager) { + const _usdtScalingPriceFeed = await deploymentManager.deploy( + 'USDT:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + USDT_PRICE_FEED_ADDRESS, // USDT / ETH price feed + 8 // decimals + ] + ); + + const _usdcScalingPriceFeed = await deploymentManager.deploy( + 'USDC:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + USDC_PRICE_FEED_ADDRESS, // USDC / ETH price feed + 8 // decimals + ] + ); + return { usdtScalingPriceFeed: _usdtScalingPriceFeed.address, usdcScalingPriceFeed: _usdcScalingPriceFeed.address }; + }, + + async enact(deploymentManager: DeploymentManager, _, { usdtScalingPriceFeed, usdcScalingPriceFeed }) { + + const trace = deploymentManager.tracer(); + + const USDT = await deploymentManager.existing( + 'USDT', + USDT_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const usdtPricefeed = await deploymentManager.existing( + 'USDT:priceFeed', + usdtScalingPriceFeed, + 'mainnet' + ); + + const USDC = await deploymentManager.existing( + 'USDC', + USDC_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const usdcPricefeed = await deploymentManager.existing( + 'USDC:priceFeed', + usdcScalingPriceFeed, + 'mainnet' + ); + + const { + governor, + comet, + cometAdmin, + configurator, + } = await deploymentManager.getContracts(); + + const usdtAssetConfig = { + asset: USDT.address, + priceFeed: usdtPricefeed.address, + decimals: await USDT.decimals(), + borrowCollateralFactor: exp(0.80, 18), + liquidateCollateralFactor: exp(0.85, 18), + liquidationFactor: exp(0.95, 18), + supplyCap: exp(50_000_000, 6), + }; + + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: usdcPricefeed.address, + decimals: 6, + borrowCollateralFactor: exp(0.80, 18), + liquidateCollateralFactor: exp(0.85, 18), + liquidationFactor: exp(0.95, 18), + supplyCap: exp(50_000_000, 6), + }; + + const mainnetActions = [ + // 1. Set new factory + { + contract: configurator, + signature: 'setFactory(address,address)', + args: [comet.address, NEW_FACTORY_ADDRESS], + }, + // 2. Add USDT as asset + { + contract: configurator, + signature: 'addAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + args: [comet.address, usdtAssetConfig], + }, + // 3. Add USDC as asset + { + contract: configurator, + signature: 'addAsset(address,(address,address,uint8,uint64,uint64,uint64,uint128))', + args: [comet.address, usdcAssetConfig], + }, + // 4. Deploy and upgrade to a new version of Comet + { + contract: cometAdmin, + signature: 'deployAndUpgradeTo(address,address)', + args: [configurator.address, comet.address], + }, + ]; + + const description = 'DESCRIPTION'; + const txn = await deploymentManager.retry(async () => + trace( + await governor.propose(...(await proposal(mainnetActions, description))) + ) + ); + + const event = txn.events.find( + (event) => event.event === 'ProposalCreated' + ); + const [proposalId] = event.args; + trace(`Created proposal ${proposalId}.`); + // second proposal + }, + + async enacted(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager) { + const { comet, configurator } = await deploymentManager.getContracts(); + + const usdtAssetIndex = Number(await comet.numAssets()) - 2; + const usdcAssetIndex = Number(await comet.numAssets()) - 1; + + const USDT = await deploymentManager.existing( + 'USDT', + USDT_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const usdtAssetConfig = { + asset: USDT.address, + priceFeed: '', + decimals: await USDT.decimals(), + borrowCollateralFactor: exp(0.80, 18), + liquidateCollateralFactor: exp(0.85, 18), + liquidationFactor: exp(0.95, 18), + supplyCap: exp(50_000_000, 6), + }; + + const USDC = await deploymentManager.existing( + 'USDC', + USDC_ADDRESS, + 'mainnet', + 'contracts/ERC20.sol:ERC20' + ); + const usdcAssetConfig = { + asset: USDC.address, + priceFeed: '', + decimals: 6, + borrowCollateralFactor: exp(0.80, 18), + liquidateCollateralFactor: exp(0.85, 18), + liquidationFactor: exp(0.95, 18), + supplyCap: exp(50_000_000, 6), + }; + + // 1. Compare USDT asset config with Comet and Configurator asset info + const cometUsdtAssetInfo = await comet.getAssetInfo(usdtAssetIndex); + expect(usdtAssetIndex).to.be.equal(cometUsdtAssetInfo.offset); + expect(usdtAssetConfig.asset).to.be.equal(cometUsdtAssetInfo.asset); + expect(exp(1, usdtAssetConfig.decimals)).to.be.equal(cometUsdtAssetInfo.scale); + expect(usdtAssetConfig.borrowCollateralFactor).to.be.equal(cometUsdtAssetInfo.borrowCollateralFactor); + expect(usdtAssetConfig.liquidateCollateralFactor).to.be.equal(cometUsdtAssetInfo.liquidateCollateralFactor); + expect(usdtAssetConfig.liquidationFactor).to.be.equal(cometUsdtAssetInfo.liquidationFactor); + expect(usdtAssetConfig.supplyCap).to.be.equal(cometUsdtAssetInfo.supplyCap); + + const configuratorUsdtAssetConfig = (await configurator.getConfiguration(comet.address)).assetConfigs[usdtAssetIndex]; + expect(usdtAssetConfig.asset).to.be.equal(configuratorUsdtAssetConfig.asset); + expect(usdtAssetConfig.decimals).to.be.equal(configuratorUsdtAssetConfig.decimals); + expect(usdtAssetConfig.borrowCollateralFactor).to.be.equal(configuratorUsdtAssetConfig.borrowCollateralFactor); + expect(usdtAssetConfig.liquidateCollateralFactor).to.be.equal(configuratorUsdtAssetConfig.liquidateCollateralFactor); + expect(usdtAssetConfig.liquidationFactor).to.be.equal(configuratorUsdtAssetConfig.liquidationFactor); + expect(usdtAssetConfig.supplyCap).to.be.equal(configuratorUsdtAssetConfig.supplyCap); + + // 2. Compare USDC asset config with Comet and Configurator asset info + const cometUsdcAssetInfo = await comet.getAssetInfo(usdcAssetIndex); + expect(usdcAssetIndex).to.be.equal(cometUsdcAssetInfo.offset); + expect(usdcAssetConfig.asset).to.be.equal(cometUsdcAssetInfo.asset); + expect(exp(1, usdcAssetConfig.decimals)).to.be.equal(cometUsdcAssetInfo.scale); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(cometUsdcAssetInfo.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(cometUsdcAssetInfo.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(cometUsdcAssetInfo.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(cometUsdcAssetInfo.supplyCap); + + const configuratorUsdcAssetConfig = (await configurator.getConfiguration(comet.address)).assetConfigs[usdcAssetIndex]; + expect(usdcAssetConfig.asset).to.be.equal(configuratorUsdcAssetConfig.asset); + expect(usdcAssetConfig.decimals).to.be.equal(configuratorUsdcAssetConfig.decimals); + expect(usdcAssetConfig.borrowCollateralFactor).to.be.equal(configuratorUsdcAssetConfig.borrowCollateralFactor); + expect(usdcAssetConfig.liquidateCollateralFactor).to.be.equal(configuratorUsdcAssetConfig.liquidateCollateralFactor); + expect(usdcAssetConfig.liquidationFactor).to.be.equal(configuratorUsdcAssetConfig.liquidationFactor); + expect(usdcAssetConfig.supplyCap).to.be.equal(configuratorUsdcAssetConfig.supplyCap); + }, +}); diff --git a/scenario/constraints/ProposalConstraint.ts b/scenario/constraints/ProposalConstraint.ts index 02ccc7407..c085cb68c 100644 --- a/scenario/constraints/ProposalConstraint.ts +++ b/scenario/constraints/ProposalConstraint.ts @@ -62,9 +62,9 @@ export class ProposalConstraint implements StaticConstra ); } - // temporary hack to skip proposal 259 - if (proposal.id.eq(259)) { - console.log('Skipping proposal 259'); + // temporary hack to skip proposal 287 + if (proposal.id.eq(287)) { + console.log('Skipping proposal 287'); continue; } From 03061185eec49968687070b8255e7533dcbd98e5 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 29 Jul 2024 13:52:19 +0300 Subject: [PATCH 2/8] fix --- scenario/LiquidationBotScenario.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scenario/LiquidationBotScenario.ts b/scenario/LiquidationBotScenario.ts index bf21963b7..f89e41ac9 100644 --- a/scenario/LiquidationBotScenario.ts +++ b/scenario/LiquidationBotScenario.ts @@ -767,7 +767,7 @@ scenario( const assetAmounts = { mainnet: { usdc: ' == 5000', // COMP - weth: ' == 7000', // CB_ETH + weth: ' == 6500', // CB_ETH usdt: ' == 5000', // COMP }, }; From 7d43f282f48da966af503608c084858bf7a26607 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 29 Jul 2024 14:17:50 +0300 Subject: [PATCH 3/8] feat: add description --- .../migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts index b34a77868..a580ff711 100644 --- a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts +++ b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts @@ -115,7 +115,7 @@ export default migration('1721989723_add_usdt_and_usdc_as_collaterals', { }, ]; - const description = 'DESCRIPTION'; + const description = '# Add USDT and USDC as collaterals into cWETHv3 on Mainnet\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes to add USDT and USDC into cWETHv3 on Ethereum network. This proposal takes the governance steps recommended and necessary to update a Compound III WETH market on Ethereum. Simulations have confirmed the market’s readiness, as much as possible, using the [Comet scenario suite](https://github.com/compound-finance/comet/tree/main/scenario). The new parameters include setting the risk parameters based on the [recommendations from Gauntlet](https://www.comp.xyz/t/add-dai-usdc-and-usdt-as-collaterals-to-weth-comets-on-mainnet-and-arbitrum/5415/2).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/893) and [forum discussion](https://www.comp.xyz/t/add-dai-usdc-and-usdt-as-collaterals-to-weth-comets-on-mainnet-and-arbitrum/5415).\n\n\n## Proposal Actions\n\nThe first proposal action sets new factory that supports USDT non-standard interface.\n\nThe second proposal action adds USDT asset as collateral with corresponding configurations.\n\nThe third proposal action adds USDC asset as collateral with corresponding configurations.\n\nThe fourth action deploys and upgrades Comet to a new version.'; const txn = await deploymentManager.retry(async () => trace( await governor.propose(...(await proposal(mainnetActions, description))) From b0032bbf2038ca9b775b846e2655019746d0e02d Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Thu, 1 Aug 2024 16:58:49 +0300 Subject: [PATCH 4/8] fix: change factory address --- .../migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts index a580ff711..b651bd5ad 100644 --- a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts +++ b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts @@ -9,7 +9,7 @@ const USDT_PRICE_FEED_ADDRESS = '0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46'; const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; const USDC_PRICE_FEED_ADDRESS = '0x986b5E1e1755e3C2440e960477f25201B0a8bbD4'; -const NEW_FACTORY_ADDRESS = '0x89128FE4Fc91038C13220E74991F9557F816c865'; +const NEW_FACTORY_ADDRESS = '0x698A949f3b4f7a5DdE236106F25Fa0eAcA0FcEF1'; export default migration('1721989723_add_usdt_and_usdc_as_collaterals', { async prepare(deploymentManager: DeploymentManager) { From 2d9b2b0f9cb86e7c16d801f342642a78f2a5395c Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 2 Aug 2024 13:59:46 +0300 Subject: [PATCH 5/8] fix: clean up --- .../migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts index b651bd5ad..9280d33b8 100644 --- a/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts +++ b/deployments/mainnet/weth/migrations/1721989723_add_usdt_and_usdc_as_collaterals.ts @@ -127,7 +127,6 @@ export default migration('1721989723_add_usdt_and_usdc_as_collaterals', { ); const [proposalId] = event.args; trace(`Created proposal ${proposalId}.`); - // second proposal }, async enacted(): Promise { From 7cf3d67a0312216765fcc86e8118926fdd10e338 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 2 Aug 2024 15:23:14 +0300 Subject: [PATCH 6/8] debug --- scenario/WithdrawScenario.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index d0bab38b9..ef764ab58 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -5,19 +5,20 @@ import { ContractReceipt } from 'ethers'; async function testWithdrawCollateral(context: CometContext, assetNum: number): Promise { const comet = await context.getComet(); - const { albert } = context.actors; + const { charles } = context.actors; const { asset: assetAddress, scale: scaleBN } = await comet.getAssetInfo(assetNum); const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(100n * scale); + console.log('charles.address:', charles.address); + expect(await collateralAsset.balanceOf(charles.address)).to.be.equal(0n); + expect(await comet.collateralBalanceOf(charles.address, collateralAsset.address)).to.be.equal(100n * scale); - // Albert withdraws 100 units of collateral from Comet - const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: 100n * scale }); + // Charles withdraws 100 units of collateral from Comet + const txn = await charles.withdrawAsset({ asset: collateralAsset.address, amount: 100n * scale }); - expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(100n * scale); - expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); + expect(await collateralAsset.balanceOf(charles.address)).to.be.equal(100n * scale); + expect(await comet.collateralBalanceOf(charles.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas } @@ -50,7 +51,7 @@ for (let i = 0; i < MAX_ASSETS; i++) { { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), cometBalances: { - albert: { [`$asset${i}`]: amountToWithdraw }, + charles: { [`$asset${i}`]: amountToWithdraw }, }, }, async (_properties, context) => { From d62d4b3ddfd9bb247b03fe3b5e5bcb14d4238d07 Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Fri, 2 Aug 2024 15:31:28 +0300 Subject: [PATCH 7/8] fix: clean up --- scenario/WithdrawScenario.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index ef764ab58..8caa59c6c 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -10,7 +10,6 @@ async function testWithdrawCollateral(context: CometContext, assetNum: number): const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - console.log('charles.address:', charles.address); expect(await collateralAsset.balanceOf(charles.address)).to.be.equal(0n); expect(await comet.collateralBalanceOf(charles.address, collateralAsset.address)).to.be.equal(100n * scale); From aa1995da9b53cae7eefca23fb1283cb833acdc9e Mon Sep 17 00:00:00 2001 From: Mikhailo Shabodyash Date: Mon, 26 Aug 2024 18:18:00 +0300 Subject: [PATCH 8/8] fix: undo previous fix --- scenario/WithdrawScenario.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scenario/WithdrawScenario.ts b/scenario/WithdrawScenario.ts index 8caa59c6c..d0bab38b9 100644 --- a/scenario/WithdrawScenario.ts +++ b/scenario/WithdrawScenario.ts @@ -5,19 +5,19 @@ import { ContractReceipt } from 'ethers'; async function testWithdrawCollateral(context: CometContext, assetNum: number): Promise { const comet = await context.getComet(); - const { charles } = context.actors; + const { albert } = context.actors; const { asset: assetAddress, scale: scaleBN } = await comet.getAssetInfo(assetNum); const collateralAsset = context.getAssetByAddress(assetAddress); const scale = scaleBN.toBigInt(); - expect(await collateralAsset.balanceOf(charles.address)).to.be.equal(0n); - expect(await comet.collateralBalanceOf(charles.address, collateralAsset.address)).to.be.equal(100n * scale); + expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(0n); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(100n * scale); - // Charles withdraws 100 units of collateral from Comet - const txn = await charles.withdrawAsset({ asset: collateralAsset.address, amount: 100n * scale }); + // Albert withdraws 100 units of collateral from Comet + const txn = await albert.withdrawAsset({ asset: collateralAsset.address, amount: 100n * scale }); - expect(await collateralAsset.balanceOf(charles.address)).to.be.equal(100n * scale); - expect(await comet.collateralBalanceOf(charles.address, collateralAsset.address)).to.be.equal(0n); + expect(await collateralAsset.balanceOf(albert.address)).to.be.equal(100n * scale); + expect(await comet.collateralBalanceOf(albert.address, collateralAsset.address)).to.be.equal(0n); return txn; // return txn to measure gas } @@ -50,7 +50,7 @@ for (let i = 0; i < MAX_ASSETS; i++) { { filter: async (ctx) => await isValidAssetIndex(ctx, i) && await isTriviallySourceable(ctx, i, amountToWithdraw), cometBalances: { - charles: { [`$asset${i}`]: amountToWithdraw }, + albert: { [`$asset${i}`]: amountToWithdraw }, }, }, async (_properties, context) => {