diff --git a/.github/workflows/deploy-market.yaml b/.github/workflows/deploy-market.yaml index b3a563ec4..675110e4b 100644 --- a/.github/workflows/deploy-market.yaml +++ b/.github/workflows/deploy-market.yaml @@ -44,6 +44,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Seacrest uses: hayesgm/seacrest@5748b3a066f517973ca2ca03d0af39bbf2b82d10 diff --git a/.github/workflows/enact-migration.yaml b/.github/workflows/enact-migration.yaml index 3d74677e2..9d0e65987 100644 --- a/.github/workflows/enact-migration.yaml +++ b/.github/workflows/enact-migration.yaml @@ -61,6 +61,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Get governance network run: | diff --git a/.github/workflows/prepare-migration.yaml b/.github/workflows/prepare-migration.yaml index 88a156cf6..673a2781d 100644 --- a/.github/workflows/prepare-migration.yaml +++ b/.github/workflows/prepare-migration.yaml @@ -44,6 +44,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Seacrest uses: hayesgm/seacrest@5748b3a066f517973ca2ca03d0af39bbf2b82d10 diff --git a/.github/workflows/run-contract-linter.yaml b/.github/workflows/run-contract-linter.yaml index 731cb5e1e..cc840f887 100644 --- a/.github/workflows/run-contract-linter.yaml +++ b/.github/workflows/run-contract-linter.yaml @@ -16,6 +16,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/run-coverage.yaml b/.github/workflows/run-coverage.yaml index cb3672b14..7eff80fba 100644 --- a/.github/workflows/run-coverage.yaml +++ b/.github/workflows/run-coverage.yaml @@ -18,6 +18,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-eslint.yaml b/.github/workflows/run-eslint.yaml index 3e9a3e05c..42b758479 100644 --- a/.github/workflows/run-eslint.yaml +++ b/.github/workflows/run-eslint.yaml @@ -16,6 +16,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-forge-tests.yaml b/.github/workflows/run-forge-tests.yaml index 42b4dcbed..700518839 100644 --- a/.github/workflows/run-forge-tests.yaml +++ b/.github/workflows/run-forge-tests.yaml @@ -31,6 +31,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} - name: Build Comet with older solc versions run: | diff --git a/.github/workflows/run-gas-profiler.yaml b/.github/workflows/run-gas-profiler.yaml index 62fb5879e..fb6718e73 100644 --- a/.github/workflows/run-gas-profiler.yaml +++ b/.github/workflows/run-gas-profiler.yaml @@ -17,6 +17,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 4446b0b42..7ecf61dc1 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, mainnet-usds, 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, mantle-usde, scroll-goerli, scroll-usdc] + bases: [ development, mainnet, mainnet-weth, mainnet-usdt, mainnet-wsteth, mainnet-usds, 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, mantle-usde, scroll-goerli, scroll-usdc, scroll-weth] name: Run scenarios env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} @@ -20,6 +20,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} runs-on: ubuntu-latest steps: - name: Checkout repository diff --git a/.github/workflows/run-semgrep.yaml b/.github/workflows/run-semgrep.yaml index 533539d05..e329c9813 100644 --- a/.github/workflows/run-semgrep.yaml +++ b/.github/workflows/run-semgrep.yaml @@ -21,6 +21,7 @@ jobs: POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} container: # A Docker image with Semgrep installed. Do not change this. image: returntocorp/semgrep diff --git a/.github/workflows/run-unit-tests.yaml b/.github/workflows/run-unit-tests.yaml index 452207832..a5e2d681d 100644 --- a/.github/workflows/run-unit-tests.yaml +++ b/.github/workflows/run-unit-tests.yaml @@ -16,6 +16,7 @@ jobs: LINEASCAN_KEY: ${{ secrets.LINEASCAN_KEY }} OPTIMISMSCAN_KEY: ${{ secrets.OPTIMISMSCAN_KEY }} MANTLESCAN_KEY: ${{ secrets.MANTLESCAN_KEY }} + SCROLLSCAN_KEY: ${{ secrets.SCROLLSCAN_KEY }} steps: - name: Checkout repository uses: actions/checkout@v4 diff --git a/deployments/mainnet/usdc/relations.ts b/deployments/mainnet/usdc/relations.ts index 2387c8daa..f4e6ec256 100644 --- a/deployments/mainnet/usdc/relations.ts +++ b/deployments/mainnet/usdc/relations.ts @@ -86,6 +86,13 @@ export default { } } }, + scrollL1ETHGateway: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, scrollL1USDCGateway: { delegates: { field: { diff --git a/deployments/mainnet/usdc/roots.json b/deployments/mainnet/usdc/roots.json index de52796a2..0f68b5e5d 100644 --- a/deployments/mainnet/usdc/roots.json +++ b/deployments/mainnet/usdc/roots.json @@ -16,5 +16,6 @@ "mantleL1CrossDomainMessenger": "0x676A795fe6E43C17c668de16730c3F690FEB7120", "mantleL1StandardBridge": "0x95fC37A27a2f68e3A647CDc081F0A89bb47c3012", "scrollMessenger": "0x6774Bcbd5ceCeF1336b5300fb5186a12DDD8b367", + "scrollL1ETHGateway": "0x7F2b8C31F88B6006c382775eea88297Ec1e3E905", "scrollL1USDCGateway": "0xf1AF3b23DE0A5Ca3CAb7261cb0061C0D779A5c7B" } \ No newline at end of file diff --git a/deployments/scroll/weth/configuration.json b/deployments/scroll/weth/configuration.json new file mode 100644 index 000000000..e377d8730 --- /dev/null +++ b/deployments/scroll/weth/configuration.json @@ -0,0 +1,60 @@ +{ + "name": "Compound WETH", + "symbol": "cWETHv3", + "baseToken": "WETH", + "baseTokenAddress": "0x5300000000000000000000000000000000000004", + "borrowMin": "0.000001e18", + "pauseGuardian": "0x0747a435b8a60070A7a111D015046d765098e4cc", + "storeFrontPriceFactor": 0.7, + "targetReserves": "5000e18", + "rates": { + "supplyKink": 0.9, + "supplySlopeLow": 0.0216, + "supplySlopeHigh": 1.125, + "supplyBase": 0, + "borrowKink": 0.9, + "borrowSlopeLow": 0.0155, + "borrowSlopeHigh": 1.26, + "borrowBase": 0.01 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "0e15", + "baseBorrowSpeed": "0e15", + "baseMinForRewards": "1e18" + }, + "assets": { + "weETH": { + "address": "0x01f0a31698C4d065659b9bdC21B3610292a1c506", + "decimals": "18", + "borrowCF": 0.9, + "liquidateCF": 0.93, + "liquidationFactor": 0.96, + "supplyCap": "20000e18" + }, + "wrsETH": { + "address": "0xa25b25548B4C98B0c7d3d27dcA5D5ca743d68b7F", + "decimals": "18", + "borrowCF": 0.88, + "liquidateCF": 0.91, + "liquidationFactor": 0.96, + "supplyCap": "4000e18" + }, + "wstETH": { + "address": "0xf610A9dfB7C89644979b4A0f27063E9e7d7Cda32", + "decimals": "18", + "borrowCF": 0.9, + "liquidateCF": 0.93, + "liquidationFactor": 0.97, + "supplyCap": "3000e18" + }, + "PufETH": { + "address": "0xc4d46E8402F476F269c379677C99F18E22Ea030e", + "decimals": "18", + "borrowCF": 0.88, + "liquidateCF": 0.91, + "liquidationFactor": 0.95, + "supplyCap": "1000e18" + } + } +} diff --git a/deployments/scroll/weth/deploy.ts b/deployments/scroll/weth/deploy.ts new file mode 100644 index 000000000..458e72bcc --- /dev/null +++ b/deployments/scroll/weth/deploy.ts @@ -0,0 +1,117 @@ +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 trace = deploymentManager.tracer(); + const ethers = deploymentManager.hre.ethers; + + const weETH = await deploymentManager.existing( + 'weETH', + '0x01f0a31698C4d065659b9bdC21B3610292a1c506', + 'scroll' + ); + const wrsETH = await deploymentManager.existing( + 'wrsETH', + '0xa25b25548B4C98B0c7d3d27dcA5D5ca743d68b7F', + 'scroll' + ); + const wstETH = await deploymentManager.existing( + 'wstETH', + '0xf610A9dfB7C89644979b4A0f27063E9e7d7Cda32', + 'scroll' + ); + const pufETH = await deploymentManager.existing( + 'PufETH', + '0xc4d46E8402F476F269c379677C99F18E22Ea030e', + 'scroll' + ); + + const COMP = await deploymentManager.existing( + 'COMP', + '0x643e160a3C3E2B7eae198f0beB1BfD2441450e86', + 'scroll' + ); + + const WETH = await deploymentManager.existing( + 'WETH', + '0x5300000000000000000000000000000000000004', + 'scroll' + ); + + const l2Messenger = await deploymentManager.existing('l2Messenger','0x781e90f1c8Fc4611c9b7497C3B47F99Ef6969CbC','scroll'); + const l2ERC20Gateway = await deploymentManager.existing('l2ERC20Gateway','0xE2b4795039517653c5Ae8C2A9BFdd783b48f447A','scroll'); + const l2ETHGateway = await deploymentManager.existing('l2ETHGateway', '0x6EA73e05AdC79974B931123675ea8F78FfdacDF0', 'scroll'); + const l2WETHGateway = await deploymentManager.existing('l2WETHGateway','0x7003E7B7186f0E6601203b99F7B8DECBfA391cf9','scroll'); + const l2WstETHGateway = await deploymentManager.existing('l2WstETHGateway', '0x8aE8f22226B9d789A36AC81474e633f8bE2856c9', 'scroll'); + + const wethConstantPriceFeed = await deploymentManager.deploy( + 'WETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + exp(1, 8) // constantPrice + ] + ); + + const weETHPriceFeed = await deploymentManager.deploy( + 'weETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x57bd9E614f542fB3d6FeF2B744f3B813f0cc1258', // weETH / ETH price feed, we treat eETH as 1:1 with ETH + 8 // decimals + ] + ); + + const wrsETHPriceFeed = await deploymentManager.deploy( + 'wrsETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x3a44916dc37Bb7D73419Fc6492d6d9Dfd8e6ddf7', // wrsETH (same as rsETH) / ETH price feed + 8 // decimals + ] + ); + + const wstETHETHPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0xE61Da4C909F7d86797a0D06Db63c34f76c9bCBDC', // wstETH / ETH price feed, we treat stETH as 1:1 with ETH + 8 // decimals + ] + ); + + const pufETHPriceFeed = await deploymentManager.deploy( + 'PufETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x7C6Da2C92caCe9F77274379Dc32a1eEE0B4C5FfD', // pufETH / ETH price feed + 8 // decimals + ] + ); + + // Import shared contracts from cUSDCv3 deployment + const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'scroll', 'usdc', true); + const cometFactory = await deploymentManager.fromDep('cometFactory', 'scroll', 'usdc', true); + const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'scroll', 'usdc', true); + const configurator = await deploymentManager.fromDep('configurator', 'scroll', 'usdc', true); + const rewards = await deploymentManager.fromDep('rewards', 'scroll', 'usdc', true); + const bulker = await deploymentManager.fromDep('bulker', 'scroll', 'usdc', true); + const localTimelock = await deploymentManager.fromDep('timelock', 'scroll', 'usdc', true); + const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'scroll', 'usdc', true); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec); + + return { + ...deployed, + bridgeReceiver, + l2Messenger, + l2ERC20Gateway, + l2ETHGateway, + l2WETHGateway, + l2WstETHGateway, + bulker, + rewards, + COMP + }; +} diff --git a/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts b/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts new file mode 100644 index 000000000..c1471cbd9 --- /dev/null +++ b/deployments/scroll/weth/migrations/1733443598_configurate_and_ens.ts @@ -0,0 +1,317 @@ +import { DeploymentManager } from '../../../../plugins/deployment_manager/DeploymentManager'; +import { ethers } from 'ethers'; +import { migration } from '../../../../plugins/deployment_manager/Migration'; +import { diffState, getCometConfig } from '../../../../plugins/deployment_manager/DiffState'; +import { + calldata, + exp, + getConfigurationStruct, + proposal, +} from '../../../../src/deploy'; +import { expect } from 'chai'; + +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 wethAmountToBridge = exp(25, 18); + +export default migration('1733443598_configurate_and_ens', { + prepare: async () => { + return {}; + }, + + enact: async ( + deploymentManager: DeploymentManager, + govDeploymentManager: DeploymentManager + ) => { + const trace = deploymentManager.tracer(); + const { utils } = ethers; + + const cometFactory = await deploymentManager.fromDep( + 'cometFactory', + 'scroll', + 'usdc' + ); + const { + bridgeReceiver, + timelock: localTimelock, + comet, + cometAdmin, + configurator, + WETH, + } = await deploymentManager.getContracts(); + + const { + scrollMessenger, + scrollL1ETHGateway, + 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 scrollChainId = 534352; + const newMarketObject = { baseSymbol: 'WETH', cometAddress: comet.address }; + const officialMarketsJSON = JSON.parse( + await ENSResolver.text(subdomainHash, ENSTextRecordKey) + ); + if (officialMarketsJSON[scrollChainId]) { + officialMarketsJSON[scrollChainId].push(newMarketObject); + } else { + officialMarketsJSON[scrollChainId] = [newMarketObject]; + } + + const configuration = await getConfigurationStruct(deploymentManager); + const setFactoryCalldata = await calldata( + configurator.populateTransaction.setFactory( + comet.address, + cometFactory.address + ) + ); + const setConfigurationCalldata = await calldata( + configurator.populateTransaction.setConfiguration( + comet.address, + configuration + ) + ); + const deployAndUpgradeToCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [configurator.address, comet.address] + ); + const depositCalldata = await calldata(WETH.populateTransaction.deposit()); + const transferCalldata = await calldata(WETH.populateTransaction.transfer(comet.address, wethAmountToBridge)); + + const l2ProposalData = utils.defaultAbiCoder.encode( + ['address[]', 'uint256[]', 'string[]', 'bytes[]'], + [ + [ + configurator.address, + configurator.address, + cometAdmin.address, + WETH.address, + WETH.address, + ], + [ + 0, + 0, + 0, + wethAmountToBridge, + 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)', + 'deposit()', + 'transfer(address,uint256)', + ], + [ + setFactoryCalldata, + setConfigurationCalldata, + deployAndUpgradeToCalldata, + depositCalldata, + transferCalldata + ], + ] + ); + + const actions = [ + // 1. Bridge ETH from Ethereum to Scroll timelock using the L1ETHGateway + { + contract: scrollL1ETHGateway, + // function depositETH(address _to,uint256 _amount,uint256 _gasLimit) + signature: 'depositETH(address,uint256,uint256)', + args: [ + localTimelock.address, + wethAmountToBridge, + 200_000, + ], + value: wethAmountToBridge + exp(0.05, 18), + }, + // 2. Set Comet configuration + deployAndUpgradeTo new Comet and wrap eth on Scroll + { + contract: scrollMessenger, + signature: 'sendMessage(address,uint256,bytes,uint256)', + args: [bridgeReceiver.address, 0, l2ProposalData, 6_000_000], + value: exp(0.15, 18), + }, + // 3. 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 cWETHv3 on Scroll network\n\n## Proposal summary\n\nCompound Growth Program [AlphaGrowth] proposes the deployment of Compound III to the Scroll network. This proposal takes the governance steps recommended and necessary to initialize a Compound III WETH market on Scroll; upon execution, cWETHv3 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/add-market-eth-on-scroll/5884/2).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/950), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/12286258750) and [forum discussion](https://www.comp.xyz/t/add-market-eth-on-scroll/5884).\n\n\n## Proposal Actions\n\nThe first proposal action sends ether to the Scroll Timelock so it can be wrapped and used to seed the reserves.\n\nThe second proposal action sets the Comet configuration and deploys a new Comet implementation on Scroll. This sends the encoded `setFactory`, `setConfiguration`, `deployAndUpgradeTo` calls across the bridge to the governance receiver on Scroll. Also it wraps and transfers ether to the Comet to seed the reserves.\n\nThe third 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 Scroll cWETHv3 market.'; + const txn = await govDeploymentManager.retry(async () => { + return 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 } = await deploymentManager.getContracts(); + + const { + timelock + } = await govDeploymentManager.getContracts(); + + // 1. + expect(await comet.getReserves()).to.be.equal(wethAmountToBridge); + + // 2. + // uncomment on on-chain proposal PR + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + expect(stateChanges).to.deep.equal({ + weETH: { + supplyCap: exp(20_000, 18) + }, + wrsETH: { + supplyCap: exp(4_000, 18) + }, + wstETH: { + supplyCap: exp(3_000, 18) + }, + PufETH: { + supplyCap: exp(1_000, 18) + } + }); + + // 3. + const ENSResolver = await govDeploymentManager.existing( + 'ENSResolver', + ENSResolverAddress + ); + const ENSRegistry = await govDeploymentManager.existing('ENSRegistry', ENSRegistryAddress); + const subdomainHash = ethers.utils.namehash(ENSSubdomain); + const officialMarketsJSON = await ENSResolver.text( + subdomainHash, + ENSTextRecordKey + ); + expect(await ENSRegistry.recordExists(subdomainHash)).to.be.equal(true); + expect(await ENSRegistry.owner(subdomainHash)).to.be.equal(timelock.address); + expect(await ENSRegistry.resolver(subdomainHash)).to.be.equal(ENSResolverAddress); + expect(await ENSRegistry.ttl(subdomainHash)).to.be.equal(0); + 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' + }, + { + baseSymbol: 'USDS', + cometAddress: '0x5D409e56D886231aDAf00c8775665AD0f9897b56' + } + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' + }, + { + baseSymbol: 'WETH', + cometAddress: '0xE36A30D249f7761327fd973001A32010b521b6Fd' + }, + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' + }, + ], + 5000: [ + { + baseSymbol: 'USDe', + cometAddress: '0x606174f62cd968d8e684c645080fa694c1D7786E' + } + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' + }, + { + baseSymbol: 'AERO', + cometAddress: '0x784efeB622244d2348d4F2522f8860B96fbEcE89' + } + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' + }, + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' + }, + { + baseSymbol: 'WETH', + cometAddress: comet.address + } + ] + }); + } +}); diff --git a/deployments/scroll/weth/relations.ts b/deployments/scroll/weth/relations.ts new file mode 100644 index 000000000..8bf9172c8 --- /dev/null +++ b/deployments/scroll/weth/relations.ts @@ -0,0 +1,52 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: 'contracts/bridges/scroll/ScrollBridgeReceiver.sol:ScrollBridgeReceiver' + }, + l2Messenger: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + l2ERC20Gateway: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + l2ETHGateway: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + l2WETHGateway: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + l2WstETHGateway: { + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + // wstETH + TransparentUpgradeableProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, +}; diff --git a/deployments/scroll/weth/roots.json b/deployments/scroll/weth/roots.json new file mode 100644 index 000000000..f46bb916a --- /dev/null +++ b/deployments/scroll/weth/roots.json @@ -0,0 +1,13 @@ +{ + "bridgeReceiver": "0xC6bf5A64896D679Cf89843DbeC6c0f5d3C9b610D", + "l2Messenger": "0x781e90f1c8Fc4611c9b7497C3B47F99Ef6969CbC", + "l2ERC20Gateway": "0xE2b4795039517653c5Ae8C2A9BFdd783b48f447A", + "l2ETHGateway": "0x6EA73e05AdC79974B931123675ea8F78FfdacDF0", + "l2WETHGateway": "0x7003E7B7186f0E6601203b99F7B8DECBfA391cf9", + "l2WstETHGateway": "0x8aE8f22226B9d789A36AC81474e633f8bE2856c9", + "comet": "0xdB7EdFa090061D9367CbEAF6bE16ECbDE596676C", + "configurator": "0xECAB0bEEa3e5DEa0c35d3E69468EAC20098032D7", + "rewards": "0x70167D30964cbFDc315ECAe02441Af747bE0c5Ee", + "bulker": "0x53C6D04e3EC7031105bAeA05B36cBc3C987C56fA", + "COMP": "0x643e160a3C3E2B7eae198f0beB1BfD2441450e86" +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index f7a92ce4b..c703c1a10 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -49,6 +49,8 @@ import optimismWethRelationConfigMap from './deployments/optimism/weth/relations import mantleRelationConfigMap from './deployments/mantle/usde/relations'; import scrollGoerliRelationConfigMap from './deployments/scroll-goerli/usdc/relations'; import scrollRelationConfigMap from './deployments/scroll/usdc/relations'; +import scrollWethRelationConfigMap from './deployments/scroll/weth/relations'; + task('accounts', 'Prints the list of accounts', async (taskArgs, hre) => { for (const account of await hre.ethers.getSigners()) console.log(account.address); @@ -73,7 +75,8 @@ const { NETWORK_PROVIDER = '', GOV_NETWORK_PROVIDER = '', GOV_NETWORK = '', - REMOTE_ACCOUNTS = '' + REMOTE_ACCOUNTS = '', + SCROLLSCAN_KEY = '' } = process.env; function* deriveAccounts(pk: string, n: number = 10) { @@ -100,6 +103,7 @@ export function requireEnv(varName, msg?: string): string { 'LINEASCAN_KEY', 'OPTIMISMSCAN_KEY', 'MANTLESCAN_KEY', + 'SCROLLSCAN_KEY' ].map((v) => requireEnv(v)); // Networks @@ -112,11 +116,16 @@ interface NetworkConfig { } const networkConfigs: NetworkConfig[] = [ - { network: 'mainnet', chainId: 1 }, - { network: 'ropsten', chainId: 3 }, - { network: 'rinkeby', chainId: 4 }, - { network: 'goerli', chainId: 5 }, - { network: 'sepolia', chainId: 11155111 }, + { + network: 'mainnet', + chainId: 1, + url: `https://rpc.ankr.com/eth/${ANKR_KEY}`, + }, + { + network: 'sepolia', + chainId: 11155111, + url: `https://rpc.ankr.com/eth_sepolia/${ANKR_KEY}`, + }, { network: 'polygon', chainId: 137, @@ -183,7 +192,7 @@ const networkConfigs: NetworkConfig[] = [ { network: 'scroll', chainId: 534352, - url: 'https://rpc.scroll.io', + url: `https://rpc.ankr.com/scroll/${ANKR_KEY}`, } ]; @@ -282,7 +291,7 @@ const config: HardhatUserConfig = { // Scroll Testnet 'scroll-goerli': ETHERSCAN_KEY, // Scroll - 'scroll': ETHERSCAN_KEY, + 'scroll': SCROLLSCAN_KEY, }, customChains: [ { @@ -426,7 +435,8 @@ const config: HardhatUserConfig = { usdc: scrollGoerliRelationConfigMap }, 'scroll': { - usdc: scrollRelationConfigMap + usdc: scrollRelationConfigMap, + weth: scrollWethRelationConfigMap } }, }, @@ -620,6 +630,12 @@ const config: HardhatUserConfig = { network: 'scroll', deployment: 'usdc', auxiliaryBase: 'mainnet' + }, + { + name: 'scroll-weth', + network: 'scroll', + deployment: 'weth', + auxiliaryBase: 'mainnet' } ], }, diff --git a/plugins/import/etherscan.ts b/plugins/import/etherscan.ts index 332c7fe2c..ba4418ca1 100644 --- a/plugins/import/etherscan.ts +++ b/plugins/import/etherscan.ts @@ -83,7 +83,7 @@ export function getEtherscanApiKey(network: string): string { optimism: process.env.OPTIMISMSCAN_KEY, mantle: process.env.MANTLESCAN_KEY, 'scroll-goerli': process.env.ETHERSCAN_KEY, - scroll: process.env.ETHERSCAN_KEY + scroll: process.env.SCROLLSCAN_KEY }[network]; if (!apiKey) { diff --git a/plugins/scenario/Runner.ts b/plugins/scenario/Runner.ts index da19c4ebc..1791e3198 100644 --- a/plugins/scenario/Runner.ts +++ b/plugins/scenario/Runner.ts @@ -153,6 +153,37 @@ export class Runner { } } + +async function retry(fn: () => Promise, retries: number = 10, timeLimit?: number, wait: number = 100) { + try { + return await asyncCallWithTimeout(fn(), timeLimit); + } catch (e) { + if (retries === 0) throw e; + if(e.reason !== 'could not detect network') + throw e; + + console.warn(`Retrying in ${wait}ms...`); + + await new Promise(ok => setTimeout(ok, wait)); + return retry(fn, retries - 1, timeLimit, wait >= 10000 ? 10000 : wait * 2); + } +} +async function asyncCallWithTimeout(asyncPromise: Promise, timeLimit: number = 5000_000) { + let timeoutHandle: string | number | NodeJS.Timeout; + + const timeoutPromise = new Promise((_resolve, reject) => { + timeoutHandle = setTimeout( + () => reject(new Error('Async call timeout limit reached')), + timeLimit + ); + }); + + return Promise.race([asyncPromise, timeoutPromise]).then(result => { + clearTimeout(timeoutHandle); + return result; + }); +} + export async function runScenarios(bases: ForkSpec[]) { const loader = await Loader.load(); const [runningScenarios, skippedScenarios] = loader.splitScenarios(); @@ -161,16 +192,20 @@ export async function runScenarios(bases: ForkSpec[]) { const results: Result[] = []; for (const base of bases) { - const world = new World(base), dm = world.deploymentManager; - const delta = await dm.runDeployScript({ allMissing: true }); - console.log(`[${base.name}] Deployed ${dm.counter} contracts, spent ${dm.spent} to initialize world 🗺`); - console.log(`[${base.name}]\n${dm.diffDelta(delta)}`); - - if (world.auxiliaryDeploymentManager) { - await world.auxiliaryDeploymentManager.spider(); - } - - const runner = new Runner(base, world); + let runner: Runner; + await retry(async () => { + const world = new World(base); + await world.initialize(base); + const dm = world.deploymentManager; + const delta = await dm.runDeployScript({ allMissing: true }); + console.log(`[${base.name}] Deployed ${dm.counter} contracts, spent ${dm.spent} to initialize world 🗺`); + console.log(`[${base.name}]\n${dm.diffDelta(delta)}`); + + if (world.auxiliaryDeploymentManager) { + await world.auxiliaryDeploymentManager.spider(); + } + runner = new Runner(base, world); + }); // NB: contexts are (still) a bit awkward // they prob dont even really need to get passed through here currently diff --git a/plugins/scenario/World.ts b/plugins/scenario/World.ts index ffc8bdb10..35c0b53c6 100644 --- a/plugins/scenario/World.ts +++ b/plugins/scenario/World.ts @@ -28,15 +28,17 @@ export class World { snapshotAuxiliaryDeploymentManager?: DeploymentManager; constructor(base: ForkSpec) { - // Q: should we really need to fork/snapshot the deployment manager? - const hre = hreForBase(base); this.base = base; + } + + async initialize(base: ForkSpec) { + const hre = await hreForBase(base); this.deploymentManager = new DeploymentManager(base.network, base.deployment, hre); + // Q: should we really need to fork/snapshot the deployment manager? this.snapshotDeploymentManager = this.deploymentManager; - if (this.base.auxiliaryBase) { const auxiliaryBase = hre.config.scenario.bases.find(b => b.name === this.base.auxiliaryBase); - this.auxiliaryDeploymentManager = new DeploymentManager(auxiliaryBase.network, auxiliaryBase.deployment, hreForBase(auxiliaryBase)); + this.auxiliaryDeploymentManager = new DeploymentManager(auxiliaryBase.network, auxiliaryBase.deployment, await hreForBase(auxiliaryBase)); this.snapshotAuxiliaryDeploymentManager = this.auxiliaryDeploymentManager; } } diff --git a/plugins/scenario/utils/hreForBase.ts b/plugins/scenario/utils/hreForBase.ts index 5609d9572..454af84e3 100644 --- a/plugins/scenario/utils/hreForBase.ts +++ b/plugins/scenario/utils/hreForBase.ts @@ -1,4 +1,4 @@ -import type { ethers } from 'ethers'; +import { ethers } from 'ethers'; import type { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'; import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { HardhatContext } from 'hardhat/internal/context'; @@ -36,7 +36,7 @@ declare module 'hardhat/internal/core/runtime-environment' { } } -export function nonForkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { +export async function nonForkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); const hardhatArguments = getEnvHardhatArguments( @@ -61,7 +61,7 @@ export function nonForkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { ); } -export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { +export async function forkedHreForBase(base: ForkSpec): Promise { const ctx: HardhatContext = HardhatContext.getHardhatContext(); const hardhatArguments = getEnvHardhatArguments(HARDHAT_PARAM_DEFINITIONS, process.env); @@ -73,6 +73,12 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { const baseNetwork = networks[base.network] as HttpNetworkUserConfig; + const provider = new ethers.providers.JsonRpcProvider(baseNetwork.url); + + // noNetwork otherwise + if(!base.blockNumber) + base.blockNumber = await provider.getBlockNumber() - 210; // arbitrary number of blocks to go back, about 1 hour + if (!baseNetwork) { throw new Error(`cannot find network config for network: ${base.network}`); } @@ -96,7 +102,7 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { defaultNetwork: 'hardhat', networks: { hardhat: forkedNetwork, - localhost + localhost: localhost }, }, }; @@ -111,7 +117,7 @@ export function forkedHreForBase(base: ForkSpec): HardhatRuntimeEnvironment { ); } -export default function hreForBase(base: ForkSpec, fork = true): HardhatRuntimeEnvironment { +export default async function hreForBase(base: ForkSpec, fork = true): Promise { if (fork) { return forkedHreForBase(base); } else { diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index a1b012390..d2040900b 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -509,6 +509,7 @@ scenario( symbol === 'WETH' ? /Transaction reverted without a reason string/ : /.^/, symbol === 'wstETH' ? /0xc2139725/ : /.^/, symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/, + symbol === 'weETH' ? /0xfb8f41b2/ : /.^/, ] ); } @@ -595,6 +596,7 @@ scenario( symbol === 'WETH' ? /Transaction reverted without a reason string/ : /.^/, symbol === 'wstETH' ? /0x00b284f2/ : /.^/, symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/, + symbol === 'weETH' ? /0xe450d38c/ : /.^/, ] ); } diff --git a/scenario/context/CometContext.ts b/scenario/context/CometContext.ts index 9687cdd1c..e72b5a3dc 100644 --- a/scenario/context/CometContext.ts +++ b/scenario/context/CometContext.ts @@ -74,7 +74,7 @@ export class CometContext { } async getCompWhales(): Promise { - const useMainnetComp = ['mainnet', 'polygon', 'arbitrum', 'base', 'optimism', 'mantle'].includes(this.world.base.network); + const useMainnetComp = ['mainnet', 'polygon', 'arbitrum', 'base', 'optimism', 'scroll', 'mantle'].includes(this.world.base.network); return COMP_WHALES[useMainnetComp ? 'mainnet' : 'testnet']; } diff --git a/scenario/utils/relayScrollMessage.ts b/scenario/utils/relayScrollMessage.ts index e6feb53d9..4b7672778 100644 --- a/scenario/utils/relayScrollMessage.ts +++ b/scenario/utils/relayScrollMessage.ts @@ -81,21 +81,21 @@ export default async function relayScrollMessage( // 2. Cross-chain message passing if (target === l2ERC20Gateway.address) { // 1a. Bridging ERC20 token - const { l1Token, _l2Token, _from, to, amount, _data } = ethers.utils.defaultAbiCoder.decode( + const [ l1Token, _l2Token, _from, to, amount, _data ] = ethers.utils.defaultAbiCoder.decode( ['address _l1Token', 'address _l2Token','address _from', 'address _to','uint256 _amount', 'bytes _data'], messageWithoutSigHash ); - + console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of ${l1Token} to user ${to}` ); } else if (target === l2ETHGateway.address){ // 1a. Bridging ETH - const { _from, to, amount, _data } = ethers.utils.defaultAbiCoder.decode( + const [ _from, to, amount, _data ] = ethers.utils.defaultAbiCoder.decode( ['address _from', 'address _to', 'uint256 _amount', 'bytes _data'], messageWithoutSigHash ); - + const oldBalance = await bridgeDeploymentManager.hre.ethers.provider.getBalance(to); const newBalance = oldBalance.add(BigNumber.from(amount)); // This is our best attempt to mimic the deposit transaction type (not supported in Hardhat) that Optimism uses to deposit ETH to an L2 address @@ -103,48 +103,48 @@ export default async function relayScrollMessage( to, ethers.utils.hexStripZeros(newBalance.toHexString()), ]); - + console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of ETH to user ${to}` ); }else if (target === l2WETHGateway.address){ // 1c. Bridging WETH - const { _l1Token, _l2Token, _from, to, amount, _data } = ethers.utils.defaultAbiCoder.decode( + const [ _l1Token, _l2Token, _from, to, amount, _data ] = ethers.utils.defaultAbiCoder.decode( ['address _l1Token', 'address _l2Token','address _from', 'address _to','uint256 _amount', 'bytes _data'], messageWithoutSigHash ); - + console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of WETH to user ${to}` ); } else if (target === l2WstETHGateway.address){ // 1d. Bridging WstETH - const { _l1Token, _l2Token, _from, to, amount, _data } = ethers.utils.defaultAbiCoder.decode( + const [ _l1Token, _l2Token, _from, to, amount, _data ] = ethers.utils.defaultAbiCoder.decode( ['address _l1Token', 'address _l2Token','address _from', 'address _to','uint256 _amount', 'bytes _data'], messageWithoutSigHash ); - + console.log( `[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Bridged over ${amount} of WstETH to user ${to}` ); } else if (target === bridgeReceiver.address) { // Cross-chain message passing - const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address === bridgeReceiver.address); + const proposalCreatedEvent = relayMessageTxn.events.find(event => event.address.toLowerCase() === bridgeReceiver.address.toLowerCase()); const { args: { id, eta } } = bridgeReceiver.interface.parseLog(proposalCreatedEvent); - + // Add the proposal to the list of open bridged proposals to be executed after all the messages have been relayed openBridgedProposals.push({ id, eta }); } else { throw new Error(`[${governanceDeploymentManager.network} -> ${bridgeDeploymentManager.network}] Unrecognized target for cross-chain message`); } } - + // Execute open bridged proposals now that all messages have been bridged for (let proposal of openBridgedProposals) { const { eta, id } = proposal; // Fast forward l2 time await setNextBlockTimestamp(bridgeDeploymentManager, eta.toNumber() + 1); - + // Execute queued proposal await setNextBaseFeeToZero(bridgeDeploymentManager); await bridgeReceiver.executeProposal(id, { gasPrice: 0 }); diff --git a/tasks/deployment_manager/task.ts b/tasks/deployment_manager/task.ts index 5e08b7e37..1a7d84997 100644 --- a/tasks/deployment_manager/task.ts +++ b/tasks/deployment_manager/task.ts @@ -7,12 +7,12 @@ import { impersonateAddress } from '../../plugins/scenario/utils'; import hreForBase from '../../plugins/scenario/utils/hreForBase'; // TODO: Don't depend on scenario's hreForBase -function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): HardhatRuntimeEnvironment { +async function getForkEnv(env: HardhatRuntimeEnvironment, deployment: string): Promise { const base = env.config.scenario.bases.find(b => b.network == env.network.name && b.deployment == deployment); if (!base) { throw new Error(`No fork spec for ${env.network.name}`); } - return hreForBase(base); + return await hreForBase(base); } function getDefaultDeployment(config: HardhatConfig, network: string): string { @@ -65,7 +65,7 @@ task('deploy', 'Deploys market') .addFlag('overwrite', 'overwrites cache') .addParam('deployment', 'The deployment to deploy') .setAction(async ({ simulate, noDeploy, noVerify, noVerifyImpl, overwrite, deployment }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const tag = `${network}/${deployment}`; const dm = new DeploymentManager( @@ -174,7 +174,7 @@ task('migrate', 'Runs migration') .addFlag('overwrite', 'overwrites artifact if exists, fails otherwise') .setAction( async ({ migration: migrationName, prepare, enact, noEnacted, simulate, overwrite, deployment, impersonate }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const dm = new DeploymentManager( network, @@ -193,7 +193,7 @@ task('migrate', 'Runs migration') const governanceBase = isBridgedDeployment ? env.config.scenario.bases.find(b => b.name === base.auxiliaryBase) : undefined; if (governanceBase) { - const governanceEnv = hreForBase(governanceBase, simulate); + const governanceEnv = await hreForBase(governanceBase, simulate); governanceDm = new DeploymentManager( governanceBase.network, governanceBase.deployment, @@ -246,7 +246,7 @@ task('deploy_and_migrate', 'Runs deploy and migration') .addParam('deployment', 'The deployment to deploy') .setAction( async ({ migration: migrationName, prepare, enact, noEnacted, simulate, overwrite, deployment, impersonate, noDeploy, noVerify, noVerifyImpl }, env) => { - const maybeForkEnv = simulate ? getForkEnv(env, deployment) : env; + const maybeForkEnv = simulate ? await getForkEnv(env, deployment) : env; const network = env.network.name; const tag = `${network}/${deployment}`; const dm = new DeploymentManager( @@ -314,7 +314,7 @@ task('deploy_and_migrate', 'Runs deploy and migration') const governanceBase = isBridgedDeployment ? env.config.scenario.bases.find(b => b.name === base.auxiliaryBase) : undefined; if (governanceBase) { - const governanceEnv = hreForBase(governanceBase, simulate); + const governanceEnv = await hreForBase(governanceBase, simulate); governanceDm = new DeploymentManager( governanceBase.network, governanceBase.deployment, diff --git a/tasks/scenario/task.ts b/tasks/scenario/task.ts index 658623144..36ddc1c1b 100644 --- a/tasks/scenario/task.ts +++ b/tasks/scenario/task.ts @@ -39,7 +39,7 @@ task('scenario:spider', 'Runs spider in preparation for scenarios') const bases: ForkSpec[] = getBasesFromTaskArgs(taskArgs.bases, env); await Promise.all(bases.map(async (base) => { if (base.network !== 'hardhat') { - let hre = hreForBase(base); + let hre = await hreForBase(base); let dm = new DeploymentManager( base.name, base.deployment,