diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index fcff8271e..7f2020873 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - 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] + 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-aero, 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 }} diff --git a/deployments/base/aero/configuration.json b/deployments/base/aero/configuration.json new file mode 100644 index 000000000..1cf9ebd97 --- /dev/null +++ b/deployments/base/aero/configuration.json @@ -0,0 +1,60 @@ +{ + "name": "Compound AERO", + "symbol": "cAEROv3", + "baseToken": "AERO", + "baseTokenAddress": "0x940181a94A35A4569E4529A3CDfB74e38FD98631", + "borrowMin": "1e18", + "pauseGuardian": "0x3cb4653f3b45f448d9100b118b75a1503281d2ee", + "storeFrontPriceFactor": 0.6, + "targetReserves": "50000000e18", + "rates": { + "supplyKink": 0.85, + "supplySlopeLow": 0.08, + "supplySlopeHigh": 11, + "supplyBase": 0, + "borrowKink": 0.85, + "borrowSlopeLow": 0.0706, + "borrowSlopeHigh": 15, + "borrowBase": 0.04 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "173611111111e0", + "baseBorrowSpeed": "173611111111e0", + "baseMinForRewards": "1000e18" + }, + "assets": { + "WETH": { + "address": "0x4200000000000000000000000000000000000006", + "decimals": "18", + "borrowCF": 0.6, + "liquidateCF": 0.65, + "liquidationFactor": 0.75, + "supplyCap": "7500e18" + }, + "USDC": { + "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "decimals": "6", + "borrowCF": 0.65, + "liquidateCF": 0.7, + "liquidationFactor": 0.8, + "supplyCap": "30000000e6" + }, + "wstETH": { + "address": "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", + "decimals": "18", + "borrowCF": 0.6, + "liquidateCF": 0.65, + "liquidationFactor": 0.75, + "supplyCap": "5000e18" + }, + "cbBTC": { + "address": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf", + "decimals": "8", + "borrowCF": 0.6, + "liquidateCF": 0.65, + "liquidationFactor": 0.75, + "supplyCap": "150e8" + } + } +} \ No newline at end of file diff --git a/deployments/base/aero/deploy.ts b/deployments/base/aero/deploy.ts new file mode 100644 index 000000000..0213e98ba --- /dev/null +++ b/deployments/base/aero/deploy.ts @@ -0,0 +1,119 @@ +import { Deployed, DeploymentManager } from '../../../plugins/deployment_manager'; +import { DeploySpec, deployComet, exp } from '../../../src/deploy'; + +export default async function deploy(deploymentManager: DeploymentManager, deploySpec: DeploySpec): Promise { + const deployed = await deployContracts(deploymentManager, deploySpec); + return deployed; +} + +async function deployContracts( + deploymentManager: DeploymentManager, + deploySpec: DeploySpec +): Promise { + const aero = await deploymentManager.existing( + 'AERO', + '0x940181a94A35A4569E4529A3CDfB74e38FD98631', + 'base' + ); + const weth = await deploymentManager.existing( + 'WETH', + '0x4200000000000000000000000000000000000006', + 'base' + ); + const usdc = await deploymentManager.existing( + 'USDC', + '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + 'base' + ); + const wstETH = await deploymentManager.existing( + 'wstETH', + '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452', + 'base' + ); + const cbETH = await deploymentManager.existing( + 'cbETH', + '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + 'base' + ); + // AERO + // AERO -> USD + const aeroUsdPriceFeed = await deploymentManager.deploy( + 'AERO:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x4EC5970fC728C5f65ba413992CD5fF6FD70fcfF0', + 8 + ] + ); + // USDC + // USDC -> USD + const usdcToUsdPriceFeed = await deploymentManager.deploy( + 'USDC:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x7e860098F58bBFC8648a4311b374B1D669a2bc6B', // USDC -> USD + 8, + ], + true + ); + // WETH + // WETH -> USD + const ethToUsdPriceFeed = await deploymentManager.deploy( + 'WETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70', // ETH -> USD + 8, // decimals + ], + true + ); + // wstETH + // wstETH -> USD + const wstETHToUsdPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/MultiplicativePriceFeed.sol', + [ + '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061', + '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70', + 8, // decimals + 'wstETH / stETH ETH / USD' + ], + true + ); + // cbBTC + // cbBTC -> USD + const cbBTCToUsdPriceFeed = await deploymentManager.deploy( + 'cbBTC:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x07DA0E54543a844a80ABE69c8A12F22B3aA59f9D', // cbBTC -> USD + 8, // decimals + ], + true + ); + + // Import shared contracts from cUSDbCv3 + const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'base', 'usdbc'); + // new comet factory + const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'base', 'usdbc'); + const configurator = await deploymentManager.fromDep('configurator', 'base', 'usdbc'); + const rewards = await deploymentManager.fromDep('rewards', 'base', 'usdbc'); + const bulker = await deploymentManager.fromDep('bulker', 'base', 'usdbc'); + const l2CrossDomainMessenger = await deploymentManager.fromDep('l2CrossDomainMessenger', 'base', 'usdbc'); + const l2StandardBridge = await deploymentManager.fromDep('l2StandardBridge', 'base', 'usdbc'); + const localTimelock = await deploymentManager.fromDep('timelock', 'base', 'usdbc'); + const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'base', 'usdbc'); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec); + + // XXX We will need to deploy a new bulker only if need to support wstETH + + return { + ...deployed, + bridgeReceiver, + l2CrossDomainMessenger, // TODO: don't have to part of roots. can be pulled via relations + l2StandardBridge, + bulker + }; +} diff --git a/deployments/base/aero/migrations/1728096598_configurate_and_ens.ts b/deployments/base/aero/migrations/1728096598_configurate_and_ens.ts new file mode 100644 index 000000000..ba8a47678 --- /dev/null +++ b/deployments/base/aero/migrations/1728096598_configurate_and_ens.ts @@ -0,0 +1,266 @@ +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { calldata, exp, getConfigurationStruct, proposal } from '../../../../src/deploy'; +import { expect } from 'chai'; +import { ethers } from 'ethers'; + +const ENSName = 'compound-community-licenses.eth'; +const ENSResolverAddress = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'; +const ENSRegistryAddress = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e'; +const ENSSubdomainLabel = 'v3-additional-grants'; +const ENSSubdomain = `${ENSSubdomainLabel}.${ENSName}`; +const ENSTextRecordKey = 'v3-official-markets'; +const baseCOMPAddress = '0x9e1028F5F1D5eDE59748FFceE5532509976840E0'; + + +export default migration('1728096598_configurate_and_ens', { + prepare: async (deploymentManager: DeploymentManager) => { + const cometFactory = await deploymentManager.deploy('cometFactory', 'CometFactory.sol', [], true); + return { newFactoryAddress: cometFactory.address }; + }, + + enact: async (deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, { newFactoryAddress }) => { + const trace = deploymentManager.tracer(); + const { utils } = ethers; + + const { + bridgeReceiver, + comet, + cometAdmin, + configurator, + rewards, + } = await deploymentManager.getContracts(); + + const { + baseL1CrossDomainMessenger, + governor, + } = await govDeploymentManager.getContracts(); + + // ENS Setup + // See also: https://docs.ens.domains/contract-api-reference/name-processing + const ENSResolver = await govDeploymentManager.existing('ENSResolver', ENSResolverAddress); + const subdomainHash = ethers.utils.namehash(ENSSubdomain); + const baseChainId = 8453; + const newMarketObject = { baseSymbol: 'AERO', cometAddress: comet.address }; + const officialMarketsJSON = JSON.parse(await ENSResolver.text(subdomainHash, ENSTextRecordKey)); + if (officialMarketsJSON[baseChainId]) { + officialMarketsJSON[baseChainId].push(newMarketObject); + } else { + officialMarketsJSON[baseChainId] = [newMarketObject]; + } + + const configuration = await getConfigurationStruct(deploymentManager); + const setFactoryCalldata = await calldata( + configurator.populateTransaction.setFactory(comet.address, newFactoryAddress) + ); + const setConfigurationCalldata = await calldata( + configurator.populateTransaction.setConfiguration(comet.address, configuration) + ); + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + const setRewardConfigCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [comet.address, baseCOMPAddress] + ); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + cometAdmin.address, + rewards.address, + ], + [ + 0, + 0, + 0, + 0, + ], + [ + 'setFactory(address,address)', + '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)[]))', + 'deployAndUpgradeTo(address,address)', + 'setRewardConfig(address,address)', + ], + [ + setFactoryCalldata, + setConfigurationCalldata, + deployAndUpgradeToCalldata, + setRewardConfigCalldata, + ] + ] + ); + + const actions = [ + // 1. Set Comet configuration + deployAndUpgradeTo new Comet, set reward config on Base, wrap ETH to WETH and transfer to Comet as reserves. + { + contract: baseL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [bridgeReceiver.address, l2ProposalData, 3_000_000] + }, + // 2. Update the list of official markets + { + target: ENSResolverAddress, + signature: 'setText(bytes32,string,string)', + calldata: ethers.utils.defaultAbiCoder.encode( + ['bytes32', 'string', 'string'], + [subdomainHash, ENSTextRecordKey, JSON.stringify(officialMarketsJSON)] + ) + }, + ]; + + const description = '# Initialize cAEROv3 on Base network\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes the deployment of Compound III to the Base network. This proposal takes the governance steps recommended and necessary to initialize a Compound III AERO market on Base; upon execution, cAEROv3 will be ready for use. 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 off of the [recommendations from Gauntlet](https://www.comp.xyz/t/gauntlet-base-aero-comet-recommendations/5790).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/937), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/11259792818) and [forum discussion](https://www.comp.xyz/t/gauntlet-base-aero-comet-recommendations/5790).\n\n\n## Proposal Actions\n\nThe first proposal action sets the CometFactory for the new Comet instance in the existing Configurator.\n\nThe second action configures the Comet instance in the Configurator.\n\nThe third action deploys an instance of the newly configured factory and upgrades the Comet instance to use that implementation.\n\nThe fourth action configures the existing rewards contract for the newly deployed Comet instance.\n\nTODO: Seed reserves.\n\nThe sixth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Ethereum Mainnet cwstETHv3 market.'; + const txn = await govDeploymentManager.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(): Promise { + return false; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { + + const { + comet, + rewards, + COMP, + } = await deploymentManager.getContracts(); + + + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + + // uncomment on on-chain proposal PR + expect(stateChanges).to.deep.equal({ + USDC: { + supplyCap: exp(30000000, 6) + }, + WETH: { + supplyCap: exp(7500, 18) + }, + wstETH: { + supplyCap: exp(5000, 18) + }, + cbBTC: { + supplyCap: exp(150, 8) + }, + baseTrackingSupplySpeed: exp(15 / 86400, 15, 18), // 173611111111 + baseTrackingBorrowSpeed: exp(15 / 86400, 15, 18), // 173611111111 + }); + + const config = await rewards.rewardConfig(comet.address); + expect(config.token).to.be.equal(COMP.address); + expect(config.rescaleFactor).to.be.equal(exp(1, 12)); + expect(config.shouldUpscale).to.be.equal(true); + + + // 5. + const ENSResolver = await govDeploymentManager.existing( + 'ENSResolver', + ENSResolverAddress + ); + const subdomainHash = ethers.utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text( + subdomainHash, + ENSTextRecordKey + ); + const officialMarkets = JSON.parse(officialMarketsJSON); + + expect(officialMarkets).to.deep.equal({ + 1: [ + { + baseSymbol: 'USDC', + cometAddress: '0xc3d688B66703497DAA19211EEdff47f25384cdc3', + }, + { + baseSymbol: 'WETH', + cometAddress: '0xA17581A9E3356d9A858b789D68B4d866e593aE94', + }, + { + baseSymbol: 'USDT', + cometAddress: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840' + }, + { + baseSymbol: 'wstETH', + cometAddress: '0x3D0bb1ccaB520A66e607822fC55BC921738fAFE3', + }, + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB', + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214', + }, + { + baseSymbol: 'WETH', + cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' + } + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445', + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07', + }, + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf', + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F', + }, + { + baseSymbol: 'AERO', + cometAddress: comet.address, + }, + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA', + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf', + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486', + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07', + }, + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44', + }, + ], + }); + } +}); \ No newline at end of file diff --git a/deployments/base/aero/relations.ts b/deployments/base/aero/relations.ts new file mode 100644 index 000000000..ac825da26 --- /dev/null +++ b/deployments/base/aero/relations.ts @@ -0,0 +1,52 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: 'contracts/bridges/optimism/OptimismBridgeReceiver.sol:OptimismBridgeReceiver' + }, + + Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + + l2CrossDomainMessenger: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + + l2StandardBridge: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + + OssifiableProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + + TransparentUpgradeableProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + +}; \ No newline at end of file diff --git a/deployments/base/aero/roots.json b/deployments/base/aero/roots.json new file mode 100644 index 000000000..fc5de7d9f --- /dev/null +++ b/deployments/base/aero/roots.json @@ -0,0 +1,10 @@ +{ + "COMP": "0x9e1028F5F1D5eDE59748FFceE5532509976840E0", + "comet": "0x784efeB622244d2348d4F2522f8860B96fbEcE89", + "configurator": "0x45939657d1CA34A8FA39A924B71D28Fe8431e581", + "rewards": "0x123964802e6ABabBE1Bc9547D72Ef1B69B00A6b1", + "bridgeReceiver": "0x18281dfC4d00905DA1aaA6731414EABa843c468A", + "l2CrossDomainMessenger": "0x4200000000000000000000000000000000000007", + "l2StandardBridge": "0x4200000000000000000000000000000000000010", + "bulker": "0x78D0677032A35c63D142a48A2037048871212a8C" +} \ No newline at end of file diff --git a/deployments/optimism/usdt/migrations/1713012100_configurate_and_ens.ts b/deployments/optimism/usdt/migrations/1713012100_configurate_and_ens.ts index d457597e7..86dcad052 100644 --- a/deployments/optimism/usdt/migrations/1713012100_configurate_and_ens.ts +++ b/deployments/optimism/usdt/migrations/1713012100_configurate_and_ens.ts @@ -126,7 +126,7 @@ export default migration('1713012100_configurate_and_ens', { mainnetUSDTAddress, [ 'function balanceOf(address account) external view returns (uint256)', - 'function approve(address,uint256) external' + 'function approve(address,uint256) external' ], govDeploymentManager.hre.ethers.provider ); @@ -184,10 +184,10 @@ export default migration('1713012100_configurate_and_ens', { ), }, ]; - + // the description has speeds. speeds will be set up on on-chain proposal const description = "# Initialize cUSDTv3 on Optimism\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes the deployment of Compound III to the Optimism network. This proposal takes the governance steps recommended and necessary to initialize a Compound III USDT market on Optimism; upon execution, cUSDTv3 will be ready for use. 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/deploy-compound-iii-on-optimism/4975/6).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/848) and [forum discussion](https://www.comp.xyz/t/deploy-compound-iii-on-optimism/4975).\n\n\n## Proposal Actions\n\nThe first proposal action sets the Comet configuration and deploys a new Comet implementation on Optimism. This sends the encoded `setFactory`, `setConfiguration` and `deployAndUpgradeTo` calls across the bridge to the governance receiver on Optimism. It also calls `setRewardConfig` on the Optimism rewards contract, to establish Optimism’s bridged version of COMP as the reward token for the deployment and set the initial supply speed to be 5 COMP/day and borrow speed to be 5 COMP/day.\n\nThe second action reduces Compound [cUSDT](https://etherscan.io/address/0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9) reserves to Timelock, in order to seed the market reserves through the Optimism L1StandardBridge.\n\nThe third action approves Optimism’s [L1StandardBridge](https://etherscan.io/address/0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1) to take Timelock's USDT, in order to seed the reserves through the bridge.\n\nThe fourth action deposits 10K USDT from mainnet to the Optimism L1StandardBridge contract to bridge to Comet.\n\nThe fifth action updates the ENS TXT record `v3-official-markets` on `v3-additional-grants.compound-community-licenses.eth`, updating the official markets JSON to include the new Optimism cUSDTv3 market"; - const txn = await govDeploymentManager.retry(async () =>{ + const txn = await govDeploymentManager.retry(async () => { return trace(await governor.propose(...(await proposal(actions, description)))); } ); @@ -199,7 +199,7 @@ export default migration('1713012100_configurate_and_ens', { }, async enacted(deploymentManager: DeploymentManager): Promise { - return false; + return true; }, async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { @@ -219,7 +219,7 @@ export default migration('1713012100_configurate_and_ens', { } = await govDeploymentManager.getContracts(); const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); - + // uncomment on on-chain proposal PR // expect(stateChanges).to.deep.equal({ // WBTC: { diff --git a/hardhat.config.ts b/hardhat.config.ts index d15407876..411476a38 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -38,6 +38,7 @@ import arbitrumUsdtRelationConfigMap from './deployments/arbitrum/usdt/relations import baseUsdbcRelationConfigMap from './deployments/base/usdbc/relations'; import baseWethRelationConfigMap from './deployments/base/weth/relations'; import baseUsdcRelationConfigMap from './deployments/base/usdc/relations'; +import baseAeroRelationConfigMap from './deployments/base/aero/relations'; import baseGoerliRelationConfigMap from './deployments/base-goerli/usdc/relations'; import baseGoerliWethRelationConfigMap from './deployments/base-goerli/weth/relations'; import lineaGoerliRelationConfigMap from './deployments/linea-goerli/usdc/relations'; @@ -72,7 +73,7 @@ const { REMOTE_ACCOUNTS = '' } = process.env; -function *deriveAccounts(pk: string, n: number = 10) { +function* deriveAccounts(pk: string, n: number = 10) { for (let i = 0; i < n; i++) yield (BigInt('0x' + pk) + BigInt(i)).toString(16); } @@ -188,7 +189,7 @@ function setupDefaultNetworkProviders(hardhatConfig: HardhatUserConfig) { getDefaultProviderURL(netConfig.network), gas: netConfig.gas || 'auto', gasPrice: netConfig.gasPrice || 'auto', - accounts: REMOTE_ACCOUNTS ? 'remote' : ( ETH_PK ? [...deriveAccounts(ETH_PK)] : { mnemonic: MNEMONIC } ), + accounts: REMOTE_ACCOUNTS ? 'remote' : (ETH_PK ? [...deriveAccounts(ETH_PK)] : { mnemonic: MNEMONIC }), }; } } @@ -374,7 +375,8 @@ const config: HardhatUserConfig = { 'base': { usdbc: baseUsdbcRelationConfigMap, weth: baseWethRelationConfigMap, - usdc: baseUsdcRelationConfigMap + usdc: baseUsdcRelationConfigMap, + aero: baseAeroRelationConfigMap }, 'base-goerli': { usdc: baseGoerliRelationConfigMap, @@ -522,6 +524,12 @@ const config: HardhatUserConfig = { deployment: 'usdc', auxiliaryBase: 'mainnet' }, + { + name: 'base-aero', + network: 'base', + deployment: 'aero', + auxiliaryBase: 'mainnet' + }, { name: 'base-goerli', network: 'base-goerli', diff --git a/scenario/TransferScenario.ts b/scenario/TransferScenario.ts index 06d7151c0..796446453 100644 --- a/scenario/TransferScenario.ts +++ b/scenario/TransferScenario.ts @@ -2,6 +2,7 @@ import { CometContext, scenario } from './context/CometContext'; import { expect } from 'chai'; import { expectApproximately, expectBase, expectRevertCustom, getInterest, hasMinBorrowGreaterThanOne, isTriviallySourceable, isValidAssetIndex, MAX_ASSETS } from './utils'; import { ContractReceipt } from 'ethers'; +import { getConfigForScenario } from './utils/scenarioHelper'; async function testTransferCollateral(context: CometContext, assetNum: number): Promise { const comet = await context.getComet(); @@ -181,8 +182,8 @@ scenario( const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); // XXX 70 seconds?! - expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); + expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); await albert.allow(betty, true); @@ -190,8 +191,8 @@ scenario( const toTransfer = 999n * scale; // XXX cannot withdraw 1000 (to ~0) const txn = await betty.transferAssetFrom({ src: albert.address, dst: betty.address, asset: baseAsset.address, amount: toTransfer }); - expectApproximately(await albert.getCometBaseBalance(), scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); + expectApproximately(await albert.getCometBaseBalance(), scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); return txn; // return txn to measure gas } @@ -249,8 +250,8 @@ scenario( const borrowRate = (await comet.getBorrowRate(utilization)).toBigInt(); // XXX 70 seconds?! - expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); - expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, 70n) + 2n); + expectApproximately(await albert.getCometBaseBalance(), 1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); + expectApproximately(await betty.getCometBaseBalance(), -1000n * scale, getInterest(1000n * scale, borrowRate, BigInt(getConfigForScenario(context).interestSeconds)) + 2n); await albert.allow(betty, true); diff --git a/scenario/utils/scenarioHelper.ts b/scenario/utils/scenarioHelper.ts new file mode 100644 index 000000000..9ef7b4d12 --- /dev/null +++ b/scenario/utils/scenarioHelper.ts @@ -0,0 +1,49 @@ +import { CometContext } from '../context/CometContext'; + +const config = { + bulkerBase: 1000000, + bulkerAsset: 5000, + bulkerComet: 5000, + bulkerBorrowBase: 1000, + bulkerBorrowAsset: 500, + liquidationBase: 100000, + liquidationBase1: 1000, + liquidationAsset: 200, + liquidationDenominator: 90, + rewardsAsset: 10000, + rewardsBase: 1000, + transferBase: 1000, + transferAsset: 5000, + interestSeconds: 110 +}; + +export function getConfigForScenario(ctx: CometContext) { + if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'wbtc') { + config.bulkerBase = 5000; + config.bulkerAsset = 200; + config.bulkerComet = 200; + config.bulkerBorrowBase = 100; + config.bulkerBorrowAsset = 50; + config.liquidationBase = 1000; + config.liquidationBase1 = 500; + config.liquidationAsset = 100; + config.rewardsAsset = 1000; + config.rewardsBase = 100; + config.transferBase = 100; + config.transferAsset = 500; + config.interestSeconds = 70; + } + if (ctx.world.base.network === 'mainnet' && ctx.world.base.deployment === 'wsteth') { + config.liquidationBase = 10000; + config.liquidationBase1 = 1000; + config.liquidationAsset = 100; + config.liquidationDenominator = 84; + config.interestSeconds = 70; + } + + if (ctx.world.base.network === 'base' && ctx.world.base.deployment === 'aero') { + config.interestSeconds = 110; + } + + return config; +} \ No newline at end of file