diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 156f1aa1c..0fecdd98c 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, 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, scroll-goerli, scroll-usdc] + bases: [ development, mainnet, mainnet-weth, mainnet-usdt, goerli, goerli-weth, sepolia-usdc, sepolia-weth, fuji, mumbai, polygon, polygon-usdt, arbitrum-usdc.e, arbitrum-usdc, arbitrum-weth, arbitrum-usdt, arbitrum-goerli-usdc, arbitrum-goerli-usdc.e, base-usdbc, base-weth, base-usdc, base-goerli, base-goerli-weth, linea-goerli, optimism-usdc, optimism-usdt, optimism-weth, scroll-goerli, scroll-usdc] name: Run scenarios env: ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }} diff --git a/deployments/optimism/weth/configuration.json b/deployments/optimism/weth/configuration.json new file mode 100644 index 000000000..9aabf9e05 --- /dev/null +++ b/deployments/optimism/weth/configuration.json @@ -0,0 +1,52 @@ +{ + "name": "Compound WETH", + "symbol": "cWETHv3", + "baseToken": "WETH", + "baseTokenAddress": "0x4200000000000000000000000000000000000006", + "pauseGuardian": "0x3fFd6c073a4ba24a113B18C8F373569640916A45", + "borrowMin": "0.000001e18", + "storeFrontPriceFactor": 0.7, + "targetReserves": "5000e18", + "rates": { + "supplyBase": 0, + "supplySlopeLow": 0.0185, + "supplyKink": 0.85, + "supplySlopeHigh": 1, + "borrowBase": 0.01, + "borrowSlopeLow": 0.014, + "borrowKink": 0.85, + "borrowSlopeHigh": 1.15 + }, + "tracking": { + "indexScale": "1e15", + "baseSupplySpeed": "46296296296e0", + "baseBorrowSpeed": "34722222222e0", + "baseMinForRewards": "1e18" + }, + "assets": { + "wstETH": { + "address": "0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb", + "decimals": "18", + "borrowCF": 0.88, + "liquidateCF": 0.93, + "liquidationFactor": 0.97, + "supplyCap": "1_300e18" + }, + "rETH": { + "address": "0x9Bcef72be871e61ED4fBbc7630889beE758eb81D", + "decimals": "18", + "borrowCF": 0.9, + "liquidateCF": 0.93, + "liquidationFactor": 0.97, + "supplyCap": "470e18" + }, + "WBTC": { + "address": "0x68f180fcCe6836688e9084f035309E29Bf0A2095", + "decimals": "8", + "borrowCF": 0.8, + "liquidateCF": 0.85, + "liquidationFactor": 0.90, + "supplyCap": "60e8" + } + } +} \ No newline at end of file diff --git a/deployments/optimism/weth/deploy.ts b/deployments/optimism/weth/deploy.ts new file mode 100644 index 000000000..9b0650811 --- /dev/null +++ b/deployments/optimism/weth/deploy.ts @@ -0,0 +1,98 @@ +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 WETH = await deploymentManager.existing( + 'WETH', + '0x4200000000000000000000000000000000000006', + 'optimism' + ); + const rETH = await deploymentManager.existing( + 'rETH', + '0x9Bcef72be871e61ED4fBbc7630889beE758eb81D', + 'optimism' + ); + const wstETH = await deploymentManager.existing( + 'wstETH', + '0x1F32b1c2345538c0c6f582fCB022739c4A194Ebb', + 'optimism' + ); + const WBTC = await deploymentManager.existing( + 'WBTC', + '0x68f180fcCe6836688e9084f035309E29Bf0A2095', + 'optimism' + ); + + const COMP = await deploymentManager.existing( + 'COMP', + '0x7e7d4467112689329f7E06571eD0E8CbAd4910eE', + 'optimism' + ); + + const wethConstantPriceFeed = await deploymentManager.deploy( + 'WETH:priceFeed', + 'pricefeeds/ConstantPriceFeed.sol', + [ + 8, // decimals + exp(1, 8) // constantPrice + ] + ); + + const rETHPriceFeed = await deploymentManager.deploy( + 'rETH:priceFeed', + 'pricefeeds/ScalingPriceFeed.sol', + [ + '0x22F3727be377781d1579B7C9222382b21c9d1a8f', // rETH / ETH price feed + 8 // decimals + ] + ); + + const wstETHPriceFeed = await deploymentManager.deploy( + 'wstETH:priceFeed', + 'pricefeeds/MultiplicativePriceFeed.sol', + [ + '0xe59EBa0D492cA53C6f46015EEa00517F2707dc77', // wstETH / stETH price feed + '0x14d2d3a82AeD4019FddDfe07E8bdc485fb0d2249', // stETH / ETH price feed + 8, // decimals + 'wstETH / ETH price feed' // description + ] + ); + + const wbtcETHPriceFeed = await deploymentManager.deploy( + 'WBTC:priceFeed', + 'pricefeeds/ReverseMultiplicativePriceFeed.sol', + [ + '0x718A5788b89454aAE3A028AE9c111A29Be6c2a6F', // WBTC / USD price feed + '0x13e3Ee699D1909E989722E753853AE30b17e08c5', // ETH / USD price feed (reversed) + 8, // decimals + 'WBTC / ETH price feed' // description + ] + ); + + // Import shared contracts from cUSDCv3 and cUSDTv3 deployments + const cometAdmin = await deploymentManager.fromDep('cometAdmin', 'optimism', 'usdc'); + // we use cometFactory from usdc deployment, because usdt deployment use the same one. + // the factory is not the latest version of comet (update for USDT on Mainnet) + // for this market it works perfectly + const cometFactory = await deploymentManager.fromDep('cometFactory', 'optimism', 'usdc'); + const $configuratorImpl = await deploymentManager.fromDep('configurator:implementation', 'optimism', 'usdc'); + const configurator = await deploymentManager.fromDep('configurator', 'optimism', 'usdc'); + const rewards = await deploymentManager.fromDep('rewards', 'optimism', 'usdc'); + const bulker = await deploymentManager.fromDep('bulker', 'optimism', 'usdc'); + const localTimelock = await deploymentManager.fromDep('timelock', 'optimism', 'usdc'); + const bridgeReceiver = await deploymentManager.fromDep('bridgeReceiver', 'optimism', 'usdc'); + + // Deploy Comet + const deployed = await deployComet(deploymentManager, deploySpec); + + return { + ...deployed, + bridgeReceiver, + bulker, + rewards, + COMP + }; +} diff --git a/deployments/optimism/weth/migrations/1720515728_configurate_and_ens.ts b/deployments/optimism/weth/migrations/1720515728_configurate_and_ens.ts new file mode 100644 index 000000000..fd15ad64b --- /dev/null +++ b/deployments/optimism/weth/migrations/1720515728_configurate_and_ens.ts @@ -0,0 +1,306 @@ +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 opCOMPAddress = '0x7e7d4467112689329f7E06571eD0E8CbAd4910eE'; +const wethAmountToBridge = exp(10, 18); + +export default migration('1720515728_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', + 'optimism', + 'usdc' + ); + const { + bridgeReceiver, + timelock: localTimelock, + comet, + cometAdmin, + configurator, + rewards, + WETH + } = await deploymentManager.getContracts(); + + const { + opL1CrossDomainMessenger, + opL1StandardBridge, + 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 opChainId = 10; + const newMarketObject = { baseSymbol: 'WETH', cometAddress: comet.address }; + const officialMarketsJSON = JSON.parse( + await ENSResolver.text(subdomainHash, ENSTextRecordKey) + ); + if (officialMarketsJSON[opChainId]) { + officialMarketsJSON[opChainId].push(newMarketObject); + } else { + officialMarketsJSON[opChainId] = [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 setRewardConfigCalldata = utils.defaultAbiCoder.encode( + ['address', 'address'], + [comet.address, opCOMPAddress] + ); + 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, + rewards.address, + WETH.address, + WETH.address, + ], + [0, 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)', + 'setRewardConfig(address,address)', + 'deposit()', + 'transfer(address,uint256)', + ], + [ + setFactoryCalldata, + setConfigurationCalldata, + deployAndUpgradeToCalldata, + setRewardConfigCalldata, + depositCalldata, + transferCalldata + ], + ] + ); + + const actions = [ + // 1. Bridge ETH from Ethereum to OP timelock using L1StandardBridge + { + contract: opL1StandardBridge, + // function depositETHTo(address _to,uint32 _minGasLimit,bytes calldata _extraData) + signature: 'depositETHTo(address,uint32,bytes)', + args: [ + localTimelock.address, + 200_000, + '0x', + ], + value: wethAmountToBridge + }, + // 2. Set Comet configuration + deployAndUpgradeTo new Comet, set Reward Config on Optimism + { + contract: opL1CrossDomainMessenger, + signature: 'sendMessage(address,bytes,uint32)', + args: [bridgeReceiver.address, l2ProposalData, 3_000_000], + }, + // 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)] + ), + }, + ]; + + // the description has speeds. speeds will be set up on on-chain proposal + const description = '# Initialize cWETHv3 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 WETH market on Optimism; 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 on the [recommendations from Gauntlet](https://www.comp.xyz/t/add-market-eth-on-optimism/5274/5).\n\nFurther detailed information can be found on the corresponding [proposal pull request](https://github.com/compound-finance/comet/pull/882), [deploy market GitHub action run](https://github.com/woof-software/comet/actions/runs/9941213214/job/27464571077) and [forum discussion](https://www.comp.xyz/t/add-market-eth-on-optimism/5274).\n\n\n## Proposal Actions\n\nThe first action bridges 10 ETH as seed reserves from Mainnet Timelock to Optimism L2 Timelock using OpL1StandardBridge.\n\nThe second 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 4 COMP/day and borrow speed to be 3 COMP/day. The last two steps are to wrap ETH into WETH and transfer seed reserves into Comet\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 Optimism 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 true; + }, + + async verify(deploymentManager: DeploymentManager, govDeploymentManager: DeploymentManager, preMigrationBlockNumber: number) { + const { + comet, + rewards, + COMP + } = await deploymentManager.getContracts(); + + const { + timelock + } = await govDeploymentManager.getContracts(); + + // 2. + // uncomment on on-chain proposal PR + const stateChanges = await diffState(comet, getCometConfig, preMigrationBlockNumber); + expect(stateChanges).to.deep.equal({ + rETH: { + supplyCap: exp(470, 18) + }, + wstETH: { + supplyCap: exp(1_300, 18) + }, + WBTC: { + supplyCap: exp(60, 8) + }, + baseTrackingSupplySpeed: exp(4 / 86400, 15, 18), // 46296296296 + baseTrackingBorrowSpeed: exp(3 / 86400, 15, 18), // 34722222222 + }); + + 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); + + // 1. + expect(await comet.getReserves()).to.be.equal(wethAmountToBridge); + + // 3. + const ENSResolver = await govDeploymentManager.existing( + 'ENSResolver', + ENSResolverAddress + ); + const ENSRegistry = await govDeploymentManager.existing('ENSRegistry', ENSRegistryAddress, 'goerli'); + 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' + }, + ], + 10: [ + { + baseSymbol: 'USDC', + cometAddress: '0x2e44e174f7D53F0212823acC11C01A11d58c5bCB' + }, + { + baseSymbol: 'USDT', + cometAddress: '0x995E394b8B2437aC8Ce61Ee0bC610D617962B214' + }, + { + baseSymbol: 'WETH', + cometAddress: comet.address + }, + ], + 137: [ + { + baseSymbol: 'USDC', + cometAddress: '0xF25212E676D1F7F89Cd72fFEe66158f541246445' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xaeB318360f27748Acb200CE616E389A6C9409a07' + }, + ], + 8453: [ + { + baseSymbol: 'USDbC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x46e6b214b524310239732D51387075E0e70970bf' + }, + { + baseSymbol: 'USDC', + cometAddress: '0xb125E6687d4313864e53df431d5425969c15Eb2F' + }, + ], + 42161: [ + { + baseSymbol: 'USDC.e', + cometAddress: '0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA' + }, + { + baseSymbol: 'USDC', + cometAddress: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf' + }, + { + baseSymbol: 'WETH', + cometAddress: '0x6f7D514bbD4aFf3BcD1140B7344b32f063dEe486' + }, + { + baseSymbol: 'USDT', + cometAddress: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07' + }, + ], + 534352: [ + { + baseSymbol: 'USDC', + cometAddress: '0xB2f97c1Bd3bf02f5e74d13f02E3e26F93D77CE44' + }, + ] + }); + } +}); diff --git a/deployments/optimism/weth/relations.ts b/deployments/optimism/weth/relations.ts new file mode 100644 index 000000000..0b4c85f7b --- /dev/null +++ b/deployments/optimism/weth/relations.ts @@ -0,0 +1,50 @@ +import baseRelationConfig from '../../relations'; + +export default { + ...baseRelationConfig, + governor: { + artifact: + 'contracts/bridges/optimism/OptimismBridgeReceiver.sol:OptimismBridgeReceiver', + }, + Proxy: { + artifact: 'contracts/ERC20.sol:ERC20', + }, + + l2CrossDomainMessenger: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + + l2StandardBridge: { + delegates: { + field: { + slot: + '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc', + }, + }, + }, + + // rETH + L2StandardERC20: { + artifact: 'contracts/ERC20.sol:ERC20' + }, + + // wstETH + OssifiableProxy: { + artifact: 'contracts/ERC20.sol:ERC20', + delegates: { + field: { + slot: '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc' + } + } + }, + + // WBTC + WBTC: { + artifact: 'contracts/ERC20.sol:ERC20' + }, +}; diff --git a/deployments/optimism/weth/roots.json b/deployments/optimism/weth/roots.json new file mode 100644 index 000000000..a167c1b41 --- /dev/null +++ b/deployments/optimism/weth/roots.json @@ -0,0 +1,10 @@ +{ + "l2CrossDomainMessenger": "0x4200000000000000000000000000000000000007", + "l2StandardBridge": "0x4200000000000000000000000000000000000010", + "comet": "0xE36A30D249f7761327fd973001A32010b521b6Fd", + "configurator": "0x84E93EC6170ED630f5ebD89A1AAE72d4F63f2713", + "rewards": "0x443EA0340cb75a160F31A440722dec7b5bc3C2E9", + "bridgeReceiver": "0xC3a73A70d1577CD5B02da0bA91C0Afc8fA434DAF", + "bulker": "0xcb3643CC8294B23171272845473dEc49739d4Ba3", + "COMP": "0x7e7d4467112689329f7E06571eD0E8CbAd4910eE" +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 180b8b4d5..9d867fc32 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -42,6 +42,7 @@ import baseGoerliWethRelationConfigMap from './deployments/base-goerli/weth/rela import lineaGoerliRelationConfigMap from './deployments/linea-goerli/usdc/relations'; import optimismRelationConfigMap from './deployments/optimism/usdc/relations'; import optimismUsdtRelationConfigMap from './deployments/optimism/usdt/relations'; +import optimismWethRelationConfigMap from './deployments/optimism/weth/relations'; import scrollGoerliRelationConfigMap from './deployments/scroll-goerli/usdc/relations'; import scrollRelationConfigMap from './deployments/scroll/usdc/relations'; @@ -382,7 +383,8 @@ const config: HardhatUserConfig = { }, optimism: { usdc: optimismRelationConfigMap, - usdt: optimismUsdtRelationConfigMap + usdt: optimismUsdtRelationConfigMap, + weth: optimismWethRelationConfigMap }, 'scroll-goerli': { usdc: scrollGoerliRelationConfigMap @@ -543,6 +545,12 @@ const config: HardhatUserConfig = { deployment: 'usdt', auxiliaryBase: 'mainnet', }, + { + name: 'optimism-weth', + network: 'optimism', + deployment: 'weth', + auxiliaryBase: 'mainnet' + }, { name: 'scroll-goerli', network: 'scroll-goerli', diff --git a/scenario/SupplyScenario.ts b/scenario/SupplyScenario.ts index ddbd993d5..f9075208b 100644 --- a/scenario/SupplyScenario.ts +++ b/scenario/SupplyScenario.ts @@ -507,7 +507,8 @@ scenario( /transfer amount exceeds spender allowance/, /Dai\/insufficient-allowance/, symbol === 'WETH' ? /Transaction reverted without a reason string/ : /.^/, - symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/ + symbol === 'wstETH' ? /0xc2139725/ : /.^/, + symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/, ] ); } @@ -592,7 +593,8 @@ scenario( /transfer amount exceeds balance/, /Dai\/insufficient-balance/, symbol === 'WETH' ? /Transaction reverted without a reason string/ : /.^/, - symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/ + symbol === 'wstETH' ? /0x00b284f2/ : /.^/, + symbol === 'WMATIC' ? /Transaction reverted without a reason string/ : /.^/, ] ); } diff --git a/src/deploy/index.ts b/src/deploy/index.ts index f912c38bf..5212bd1d9 100644 --- a/src/deploy/index.ts +++ b/src/deploy/index.ts @@ -135,7 +135,8 @@ export const WHALES = { ], optimism: [ '0x2A82Ae142b2e62Cb7D10b55E323ACB1Cab663a26', // OP whale - '0x8af3827a41c26c7f32c81e93bb66e837e0210d5c' // USDC whale + '0x8af3827a41c26c7f32c81e93bb66e837e0210d5c', // USDC whale + '0xc45A479877e1e9Dfe9FcD4056c699575a1045dAA', // wstETH whale ] };