diff --git a/.env.example b/.env.example index c15c2be2..0aec71b8 100644 --- a/.env.example +++ b/.env.example @@ -4,33 +4,45 @@ # RPCs # ############################ -RPC_ETH_MAINNET= -RPC_ETH_SEPOLIA= +# ID of the L1 chain. For example, 1 is the ID of the Ethereum Mainnet. +L1_CHAIN_ID=1 -RPC_OPT_MAINNET=https://mainnet.optimism.io -RPC_OPT_SEPOLIA=https://sepolia.optimism.io +# ID of the L2 chain. For example, 1 is the ID of the Seneium Mainnet. +L2_CHAIN_ID=1868 + +# URL of the L1 RPC. For example, https://sepolia.infura.io/v3/ is the URL of the Sepolia testnet. +L1_PRC_URL=https://sepolia.infura.io/v3/ + +# URL of the L2 RPC. For example, https://optimism-sepolia.infura.io/v3/ is the URL of the Optimism testnet. +L2_PRC_URL=https://optimism-sepolia.infura.io/v3/ + +# Address of the rollup cross-domain messenger. Can be found in rollup docs. +L1_CROSSDOMAIN_MESSENGER=0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 +L2_CROSSDOMAIN_MESSENGER=0x4200000000000000000000000000000000000007 + +# Portal for relayer +L1_L2_PORTAL=0x16Fc5058F25648194471939df75CF27A2fdC48BC + +# Skip interactive prompts during L2 deployment if set to true +L2_DEPLOY_SKIP_PROMPTS=false # ############################ # Etherscan # ############################ -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_OPT= +L1_BLOCK_EXPLORER_API_KEY= +L2_BLOCK_EXPLORER_API_KEY= # ############################ # Bridge/Gateway Deployment # ############################ -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "sepolia". -NETWORK=mainnet - # Run deployment in the forking network instead of public ones FORKING=true # Private key of the deployer account used for deployment process -ETH_DEPLOYER_PRIVATE_KEY= -OPT_DEPLOYER_PRIVATE_KEY= +L1_DEPLOYER_PRIVATE_KEY= +L2_DEPLOYER_PRIVATE_KEY= # Address of bridge executor. GOV_BRIDGE_EXECUTOR= @@ -148,8 +160,6 @@ L2_WITHDRAWALS_DISABLERS=[] # Integration Acceptance & E2E Testing # ############################ -TESTING_OPT_NETWORK= - TESTING_OPT_L1_LIDO= TESTING_OPT_L1_REBASABLE_TOKEN= TESTING_OPT_L1_NON_REBASABLE_TOKEN= diff --git a/.env.steth.opt_mainnet b/.env.steth.opt_mainnet index f4462cf5..359f3267 100644 --- a/.env.steth.opt_mainnet +++ b/.env.steth.opt_mainnet @@ -4,33 +4,32 @@ # RPCs # ############################ -RPC_ETH_SEPOLIA=https://sepolia.infura.io/v3/ -RPC_OPT_SEPOLIA=https://optimism-sepolia.infura.io/v3/ +L1_CHAIN_ID=10 +L2_CHAIN_ID=11155420 -RPC_ETH_MAINNET=https://mainnet.infura.io/v3/ -RPC_OPT_MAINNET=https://optimism-mainnet.infura.io/v3/ +L1_PRC_URL=https://sepolia.infura.io/v3/ +L2_PRC_URL=https://optimism-sepolia.infura.io/v3/ + +L1_CROSSDOMAIN_MESSENGER=0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 +L2_CROSSDOMAIN_MESSENGER=0x4200000000000000000000000000000000000007 # ############################ # Etherscan # ############################ -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_OPT= +L1_BLOCK_EXPLORER_API_KEY= +L2_BLOCK_EXPLORER_API_KEY= # ############################ # Bridge/Gateway Deployment # ############################ -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "sepolia". -NETWORK=mainnet - # Run deployment in the forking network instead of public ones FORKING=false # Private key of the deployer account used for deployment process -ETH_DEPLOYER_PRIVATE_KEY= -OPT_DEPLOYER_PRIVATE_KEY= +L1_DEPLOYER_PRIVATE_KEY= +L2_DEPLOYER_PRIVATE_KEY= # Address of bridge executor. GOV_BRIDGE_EXECUTOR=0xefa0db536d2c8089685630fafe88cf7805966fc3 @@ -150,8 +149,6 @@ L2_WITHDRAWALS_DISABLERS=["0xEfa0dB536d2c8089685630fafe88CF7805966FC3","0x4Cf8fE # Integration & E2E Testing # ############################ -TESTING_OPT_NETWORK=sepolia - TESTING_OPT_L1_LIDO= TESTING_OPT_L1_REBASABLE_TOKEN= TESTING_OPT_L1_NON_REBASABLE_TOKEN= diff --git a/.env.steth.opt_sepolia b/.env.steth.opt_sepolia index 7ab45379..48c78f00 100644 --- a/.env.steth.opt_sepolia +++ b/.env.steth.opt_sepolia @@ -4,30 +4,32 @@ # RPCs # ############################ -RPC_ETH_SEPOLIA=https://sepolia.infura.io/v3/ -RPC_OPT_SEPOLIA=https://optimism-sepolia.infura.io/v3/ +L1_CHAIN_ID=10 +L2_CHAIN_ID=11155420 + +L1_PRC_URL=https://sepolia.infura.io/v3/ +L2_PRC_URL=https://optimism-sepolia.infura.io/v3/ + +L1_CROSSDOMAIN_MESSENGER=0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1 +L2_CROSSDOMAIN_MESSENGER=0x4200000000000000000000000000000000000007 # ############################ # Etherscan # ############################ -ETHERSCAN_API_KEY_ETH= -ETHERSCAN_API_KEY_OPT= +L1_BLOCK_EXPLORER_API_KEY= +L2_BLOCK_EXPLORER_API_KEY= # ############################ # Bridge/Gateway Deployment # ############################ -# Name of the network environments used by deployment scripts. -# Might be one of: "mainnet", "sepolia". -NETWORK=sepolia - # Run deployment in the forking network instead of public ones FORKING=false # Private key of the deployer account used for deployment process -ETH_DEPLOYER_PRIVATE_KEY= -OPT_DEPLOYER_PRIVATE_KEY= +L1_DEPLOYER_PRIVATE_KEY= +L2_DEPLOYER_PRIVATE_KEY= # Address of bridge executor. GOV_BRIDGE_EXECUTOR= @@ -145,8 +147,6 @@ L2_WITHDRAWALS_DISABLERS="["0xf695357C66bA514150Da95b189acb37b46DDe602", "0xa5F1 # Integration & E2E Testing # ############################ -TESTING_OPT_NETWORK=sepolia - TESTING_OPT_L1_LIDO=0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af TESTING_OPT_L1_REBASABLE_TOKEN=0x3e3FE7dBc6B4C189E7128855dD526361c49b40Af TESTING_OPT_L1_NON_REBASABLE_TOKEN=0xB82381A3fBD3FaFA77B3a7bE693342618240067b diff --git a/.github/workflows/storage-layout-update.yml b/.github/workflows/storage-layout-update.yml index 689c56b5..37300a9e 100644 --- a/.github/workflows/storage-layout-update.yml +++ b/.github/workflows/storage-layout-update.yml @@ -3,6 +3,11 @@ name: Update .storage-layout on: workflow_dispatch: +permissions: + contents: write + issues: write + pull-requests: write + jobs: assert: runs-on: ubuntu-latest diff --git a/.storage-layout b/.storage-layout index a2b1b3e3..48103c0a 100644 --- a/.storage-layout +++ b/.storage-layout @@ -5,125 +5,196 @@ ➡ BridgingManager ======================= + +╭--------+---------------------------------------------------+------+--------+-------+-----------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|--------|---------------------------------------------------|------|--------|-------|-----------------------------------------------| ++====================================================================================================================================+ | _roles | mapping(bytes32 => struct AccessControl.RoleData) | 0 | 0 | 32 | contracts/BridgingManager.sol:BridgingManager | +╰--------+---------------------------------------------------+------+--------+-------+-----------------------------------------------╯ + ======================= ➡ CrossDomainEnabled ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ ERC20Bridged ======================= + +╭-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|-------------|-------------------------------------------------|------|--------|-------|-----------------------------------------------| ++=======================================================================================================================================+ | totalSupply | uint256 | 0 | 0 | 32 | contracts/token/ERC20Bridged.sol:ERC20Bridged | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------| | balanceOf | mapping(address => uint256) | 1 | 0 | 32 | contracts/token/ERC20Bridged.sol:ERC20Bridged | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------| | allowance | mapping(address => mapping(address => uint256)) | 2 | 0 | 32 | contracts/token/ERC20Bridged.sol:ERC20Bridged | +╰-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------╯ + ======================= ➡ ERC20BridgedPermit ======================= + +╭-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|-------------|-------------------------------------------------|------|--------|-------|-----------------------------------------------------------| ++===================================================================================================================================================+ | totalSupply | uint256 | 0 | 0 | 32 | contracts/token/ERC20BridgedPermit.sol:ERC20BridgedPermit | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------------------| | balanceOf | mapping(address => uint256) | 1 | 0 | 32 | contracts/token/ERC20BridgedPermit.sol:ERC20BridgedPermit | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------------------| | allowance | mapping(address => mapping(address => uint256)) | 2 | 0 | 32 | contracts/token/ERC20BridgedPermit.sol:ERC20BridgedPermit | +╰-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------------------------╯ + ======================= ➡ ERC20Core ======================= + +╭-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|-------------|-------------------------------------------------|------|--------|-------|-----------------------------------------| ++=================================================================================================================================+ | totalSupply | uint256 | 0 | 0 | 32 | contracts/token/ERC20Core.sol:ERC20Core | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------| | balanceOf | mapping(address => uint256) | 1 | 0 | 32 | contracts/token/ERC20Core.sol:ERC20Core | +|-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------| | allowance | mapping(address => mapping(address => uint256)) | 2 | 0 | 32 | contracts/token/ERC20Core.sol:ERC20Core | +╰-------------+-------------------------------------------------+------+--------+-------+-----------------------------------------╯ + ======================= ➡ ERC20Metadata ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ ERC20RebasableBridged ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ ERC20RebasableBridgedPermit ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ L1LidoTokensBridge ======================= + +╭--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|--------|---------------------------------------------------|------|--------|-------|--------------------------------------------------------------| ++===================================================================================================================================================+ | _roles | mapping(bytes32 => struct AccessControl.RoleData) | 0 | 0 | 32 | contracts/optimism/L1LidoTokensBridge.sol:L1LidoTokensBridge | +╰--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------------╯ + ======================= ➡ L2ERC20ExtendedTokensBridge ======================= + +╭--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|--------|---------------------------------------------------|------|--------|-------|--------------------------------------------------------------------------------| ++=====================================================================================================================================================================+ | _roles | mapping(bytes32 => struct AccessControl.RoleData) | 0 | 0 | 32 | contracts/optimism/L2ERC20ExtendedTokensBridge.sol:L2ERC20ExtendedTokensBridge | +╰--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------------------------------╯ + ======================= ➡ OpStackTokenRatePusher ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ OssifiableProxy ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ RebasableAndNonRebasableTokens ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + ======================= ➡ TokenRateNotifier ======================= + +╭-----------+-----------+------+--------+-------+--------------------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|-----------|-----------|------|--------|-------|--------------------------------------------------------| ++========================================================================================================+ | _owner | address | 0 | 0 | 20 | contracts/lido/TokenRateNotifier.sol:TokenRateNotifier | +|-----------+-----------+------+--------+-------+--------------------------------------------------------| | observers | address[] | 1 | 0 | 32 | contracts/lido/TokenRateNotifier.sol:TokenRateNotifier | +╰-----------+-----------+------+--------+-------+--------------------------------------------------------╯ + ======================= ➡ TokenRateOracle ======================= + +╭--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|--------|---------------------------------------------------|------|--------|-------|--------------------------------------------------------| ++=============================================================================================================================================+ | _roles | mapping(bytes32 => struct AccessControl.RoleData) | 0 | 0 | 32 | contracts/optimism/TokenRateOracle.sol:TokenRateOracle | +╰--------+---------------------------------------------------+------+--------+-------+--------------------------------------------------------╯ + ======================= ➡ Versioned ======================= + +╭------+------+------+--------+-------+----------╮ | Name | Type | Slot | Offset | Bytes | Contract | -|------|------|------|--------|-------|----------| ++================================================+ +╰------+------+------+--------+-------+----------╯ + diff --git a/README.md b/README.md index bb834dc3..6a918475 100644 --- a/README.md +++ b/README.md @@ -52,10 +52,9 @@ The configuration of the deployment scripts happens via the ENV variables. The f - [`L2_TOKEN`](#L2_TOKEN) - address of the non-rebasable token on L2. - [`L2_TOKEN_RATE_ORACLE`](#L2_TOKEN_RATE_ORACLE) - address of token rate oracle on L2. - [`GOV_BRIDGE_EXECUTOR`](#GOV_BRIDGE_EXECUTOR) - address of bridge executor. -- [`NETWORK`](#NETWORK) - name of the network environments used by deployment scripts. Allowed values: `mainnet`, `sepolia`. - [`FORKING`](#FORKING) - run deployment in the forking network instead of real ones -- [`ETH_DEPLOYER_PRIVATE_KEY`](#ETH_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Ethereum network is used during the deployment process. -- [`OPT_DEPLOYER_PRIVATE_KEY`](#OPT_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Optimism network is used during the deployment process. +- [`L1_DEPLOYER_PRIVATE_KEY`](#L1_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Ethereum network is used during the deployment process. +- [`L2_DEPLOYER_PRIVATE_KEY`](#L2_DEPLOYER_PRIVATE_KEY) - The private key of the deployer account in the Optimism network is used during the deployment process. - [`L1_PROXY_ADMIN`](#L1_PROXY_ADMIN) - The address to grant admin rights of the `OssifiableProxy` on the L1 bridge - [`L1_BRIDGE_ADMIN`](#L1_BRIDGE_ADMIN) - Address to grant the `DEFAULT_ADMIN_ROLE` on the L1 bridge - [`L2_PROXY_ADMIN`](#L2_PROXY_ADMIN) - The address to grant admin rights of the `OssifiableProxy` on the L2 bridge @@ -101,14 +100,14 @@ npm run optimism:test:unit ### Integration tests -Before running integration tests, run the hardhat forked nodes in the standalone tabs corresponding to `TESTING_OPT_NETWORK` env variable or if it's not set use `mainnet` network. Example of the commands for the `mainnet` network: +Before running integration tests, run the hardhat forked nodes in the standalone tabs. Example of the commands: ```bash -# Required to run Optimism integraton tests -npm run fork:eth:mainnet +# Required to run integration tests +npm run fork:l1 -# Required to run Optimism integration tests -npm run fork:opt:mainnet +# Required to run integration tests +npm run fork:l2 The integration tests might be run via the following commands: @@ -129,7 +128,6 @@ TESTING_USE_DEPLOYED_CONTRACTS=true TESTING_L1_TOKENS_HOLDER= # Addresses of the Optimism bridge -TESTING_OPT_NETWORK= TESTING_OPT_L1_TOKEN= TESTING_OPT_L2_TOKEN= TESTING_OPT_L1_ERC20_TOKEN_BRIDGE= @@ -160,7 +158,6 @@ Additionally, tests might be run on the deployed contracts. To do it, set the fo TESTING_PRIVATE_KEY= # Addresses of the Optimism bridge -TESTING_OPT_NETWORK= TESTING_OPT_L1_TOKEN= TESTING_OPT_L2_TOKEN= TESTING_OPT_L1_ERC20_TOKEN_BRIDGE= @@ -181,39 +178,24 @@ The configuration of the project happens via set of ENV variables. The full list ### RPCs -#### `RPC_URL_ETH_MAINNET` +#### `L1_PRC_URL` -Address of the RPC node for **Mainnet** Ethereum network. +Address of the RPC node for **L1** Ethereum network. -#### `RPC_ETH_SEPOLIA` - -Address of the RPC node for **Sepolia** Ethereum network. - -#### `RPC_OPT_SEPOLIA` - -Address of the RPC node for **Sepolia** Optimism network. - -#### `RPC_OPT_MAINNET` - -> **Warning** -> -> Please, don't use the default value for production deployments! The default RPC node might not be available or fail suddenly during the request. - -Address of the RPC node for **Mainnet** Optimism network. - -> Default value: `https://mainnet.optimism.io` +#### `L2_PRC_URL` +Address of the RPC node for **L2** Ethereum network. ### Etherscan Below variables are required for successfull verification of the contracts on block explorer for certain networks. -#### `ETHERSCAN_API_KEY_ETH` +#### `L1_BLOCK_EXPLORER_API_KEY` API key from the [Etherscan](https://etherscan.io/) block explorer. See details here: https://info.etherscan.com/api-keys/ -#### `ETHERSCAN_API_KEY_OPT` +#### `L2_BLOCK_EXPLORER_API_KEY` API key from the [Optimistic Ethereum](https://optimistic.etherscan.io/) block explorer. @@ -229,23 +211,17 @@ Address of the existing non-rebasable token to deploy a new bridge for on the Et Address of the existing rebasable token to deploy new bridge for on the Ethereum chain. -#### `NETWORK` - -> Default value: `mainnet` - -Name of the network environments used by deployment scripts. Might be one of: `mainnet`, `sepolia`. - #### `FORKING` Run deployment in the forking network instead of public ones > Default value: `true` -#### `ETH_DEPLOYER_PRIVATE_KEY` +#### `L1_DEPLOYER_PRIVATE_KEY` The private key of the deployer account in the Ethereum network is used during the deployment process. -#### `OPT_DEPLOYER_PRIVATE_KEY` +#### `L2_DEPLOYER_PRIVATE_KEY` The private key of the deployer account in the Optimism network is used during the deployment process. @@ -345,13 +321,13 @@ The array of addresses to grant `WITHDRAWALS_ENABLER_ROLE` on L2 bridge/gateway. The array of addresses to grant `WITHDRAWALS_DISABLER_ROLE` on L2 bridge/gateway. The value must be in the form of JSON array of strings. For example: `["0x00000000219ab540356cbb839cbe05303d7705fa","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]` -### Acceptance Integration & E2E Testing +#### `L2_DEPLOY_SKIP_PROMPTS` -The following variables are used in the process of the Integration & E2E testing. +Skip interactive prompts during L2 deployment if set to true. -#### `TESTING_OPT_NETWORK` +### Acceptance Integration & E2E Testing -Name of the network environments used for Optimism Integration & E2E testing. Might be one of: `mainnet`, `sepolia`. +The following variables are used in the process of the Integration & E2E testing. #### `TESTING_OPT_L1_TOKEN` @@ -405,3 +381,10 @@ The test Ether might be retrived via [Paradigm Faucet](https://faucet.paradigm.x The private key from the address which holds 50+% TLDO +### Cross-Chain Relayer + +Utility that relays messages to L2. + +#### `L1_L2_PORTAL` + +An address of portal that relays messages. diff --git a/hardhat.config.ts b/hardhat.config.ts index d5704e34..866158a3 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,7 +1,7 @@ import * as dotenv from "dotenv"; import { HardhatUserConfig } from "hardhat/config"; -import "@nomiclabs/hardhat-etherscan"; +import "@nomicfoundation/hardhat-verify"; import "@nomiclabs/hardhat-waffle"; import "@typechain/hardhat"; import "hardhat-gas-reporter"; @@ -38,37 +38,18 @@ const config: HardhatUserConfig = { } } }, - // Ethereum Public Chains - eth_mainnet: { - url: env.string("RPC_ETH_MAINNET", ""), + l1: { + url: env.string("L1_PRC_URL", "") }, - eth_sepolia: { - url: env.string("RPC_ETH_SEPOLIA", ""), + l2: { + url: env.string("L2_PRC_URL", "") }, - - // Ethereum Fork Chains - eth_mainnet_fork: { - url: "http://localhost:8545", - }, - eth_sepolia_fork: { - url: "http://localhost:8545", - }, - - // Optimism Public Chains - opt_mainnet: { - url: env.string("RPC_OPT_MAINNET", ""), - }, - opt_sepolia: { - url: env.string("RPC_OPT_SEPOLIA", ""), - }, - - // Optimism Fork Chains - opt_mainnet_fork: { - url: "http://localhost:9545", - }, - opt_sepolia_fork: { - url: "http://localhost:9545", + l1_fork: { + url: "http://localhost:8545" }, + l2_fork: { + url: "http://localhost:9545" + } }, gasReporter: { enabled: env.string("REPORT_GAS", "false") !== "false", @@ -76,29 +57,26 @@ const config: HardhatUserConfig = { }, etherscan: { apiKey: { - mainnet: env.string("ETHERSCAN_API_KEY_ETH", ""), - sepolia: env.string("ETHERSCAN_API_KEY_ETH", ""), - optimisticEthereum: env.string("ETHERSCAN_API_KEY_OPT", ""), - "opt_sepolia": env.string("ETHERSCAN_API_KEY_OPT", ""), + "l1": env.string("L1_BLOCK_EXPLORER_API_KEY", ""), + "l2": env.string("L2_BLOCK_EXPLORER_API_KEY", ""), }, - customChains: [ { - network: 'sepolia', - chainId: 11155111, + network: 'l1', + chainId: env.number("L1_CHAIN_ID", ""), urls: { - apiURL: 'https://api-sepolia.etherscan.io/api', - browserURL: 'https://sepolia.etherscan.io', + apiURL: env.string("L1_BLOCK_EXPLORER_API_URL", ""), + browserURL: env.string("L1_BLOCK_EXPLORER_BROWSER_URL", ""), }, }, { - network: 'opt_sepolia', - chainId: 11155420, - urls: { - apiURL: 'https://api-sepolia-optimism.etherscan.io/api', - browserURL: 'https://sepolia-optimism.etherscan.io', - }, + network: 'l2', + chainId: env.number("L2_CHAIN_ID", ""), + urls: { + apiURL: env.string("L2_BLOCK_EXPLORER_API_URL", ""), + browserURL: env.string("L2_BLOCK_EXPLORER_BROWSER_URL", ""), }, + }, ], }, typechain: { diff --git a/package-lock.json b/package-lock.json index 2d87dbd2..314c0e65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,8 @@ "p-limit": "3.1.0" }, "devDependencies": { + "@nomicfoundation/hardhat-verify": "^2.0.11", "@nomiclabs/hardhat-ethers": "^2.0.6", - "@nomiclabs/hardhat-etherscan": "^3.1.8", "@nomiclabs/hardhat-waffle": "^2.0.3", "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^2.3.1", @@ -39,7 +39,7 @@ "ethereum-waffle": "^3.4.4", "ethereumjs-util": "^7.0.8", "ethers": "^5.6.2", - "hardhat": "^2.12.2", + "hardhat": "^2.22.15", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.6.1", "prettier-plugin-solidity": "^1.0.0-beta.13", @@ -1532,131 +1532,82 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.5.tgz", - "integrity": "sha512-dPSM9DuI1sr71gqWUMgLo8MjHQWO4+WNDm3iWaT6P4vUFJReZX5qwA5X+3UwIPBry8GvNY084u7yWUvB3/8rqA==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.4.tgz", + "integrity": "sha512-YgrSuT3yo5ZQkbvBGqQ7hG+RDvz3YygSkddg4tb1Z0Y6pLXFzwrcEwWaJCFAVeeZxdxGfCgGMUYgRVneK+WXkw==", "dev": true, + "dependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.6.4", + "@nomicfoundation/edr-darwin-x64": "0.6.4", + "@nomicfoundation/edr-linux-arm64-gnu": "0.6.4", + "@nomicfoundation/edr-linux-arm64-musl": "0.6.4", + "@nomicfoundation/edr-linux-x64-gnu": "0.6.4", + "@nomicfoundation/edr-linux-x64-musl": "0.6.4", + "@nomicfoundation/edr-win32-x64-msvc": "0.6.4" + }, "engines": { "node": ">= 18" - }, - "optionalDependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.3.5", - "@nomicfoundation/edr-darwin-x64": "0.3.5", - "@nomicfoundation/edr-linux-arm64-gnu": "0.3.5", - "@nomicfoundation/edr-linux-arm64-musl": "0.3.5", - "@nomicfoundation/edr-linux-x64-gnu": "0.3.5", - "@nomicfoundation/edr-linux-x64-musl": "0.3.5", - "@nomicfoundation/edr-win32-x64-msvc": "0.3.5" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.5.tgz", - "integrity": "sha512-gIXUIiPMUy6roLHpNlxf15DumU7/YhffUf7XIB+WUjMecaySfTGyZsTGnCMJZqrDyiYqWPyPKwCV/2u/jqFAUg==", - "cpu": [ - "arm64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.4.tgz", + "integrity": "sha512-QNQErISLgssV9+qia8sIjRANqtbW8snSDvjspixT/kSQ5ZSGxxctTg7x72wPSrcu8+EBEveIe5uqENIp5GH8HQ==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.5.tgz", - "integrity": "sha512-0MrpOCXUK8gmplpYZ2Cy0holHEylvWoNeecFcrP2WJ5DLQzrB23U5JU2MvUzOJ7aL76Za1VXNBWi/UeTWdHM+w==", - "cpu": [ - "x64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.4.tgz", + "integrity": "sha512-cjVmREiwByyc9+oGfvAh49IAw+oVJHF9WWYRD+Tm/ZlSpnEVWxrGNBak2bd/JSYjn+mZE7gmWS4SMRi4nKaLUg==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.5.tgz", - "integrity": "sha512-aw9f7AZMiY1dZFNePJGKho2k+nEgFgzUAyyukiKfSqUIMXoFXMf1U3Ujv848czrSq9c5XGcdDa2xnEf3daU3xg==", - "cpu": [ - "arm64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.4.tgz", + "integrity": "sha512-96o9kRIVD6W5VkgKvUOGpWyUGInVQ5BRlME2Fa36YoNsRQMaKtmYJEU0ACosYES6ZTpYC8U5sjMulvPtVoEfOA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.5.tgz", - "integrity": "sha512-cVFRQjyABBlsbDj+XTczYBfrCHprZ6YNzN8gGGSqAh+UGIJkAIRomK6ar27GyJLNx3HkgbuDoi/9kA0zOo/95w==", - "cpu": [ - "arm64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.4.tgz", + "integrity": "sha512-+JVEW9e5plHrUfQlSgkEj/UONrIU6rADTEk+Yp9pbe+mzNkJdfJYhs5JYiLQRP4OjxH4QOrXI97bKU6FcEbt5Q==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.5.tgz", - "integrity": "sha512-CjOg85DfR1Vt0fQWn5U0qi26DATK9tVzo3YOZEyI0JBsnqvk43fUTPv3uUAWBrPIRg5O5kOc9xG13hSpCBBxBg==", - "cpu": [ - "x64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.4.tgz", + "integrity": "sha512-nzYWW+fO3EZItOeP4CrdMgDXfaGBIBkKg0Y/7ySpUxLqzut40O4Mb0/+quqLAFkacUSWMlFp8nsmypJfOH5zoA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.5.tgz", - "integrity": "sha512-hvX8bBGpBydAVevzK8jsu2FlqVZK1RrCyTX6wGHnltgMuBaoGLHYtNHiFpteOaJw2byYMiORc2bvj+98LhJ0Ew==", - "cpu": [ - "x64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.4.tgz", + "integrity": "sha512-QFRoE9qSQ2boRrVeQ1HdzU+XN7NUgwZ1SIy5DQt4d7jCP+5qTNsq8LBNcqhRBOATgO63nsweNUhxX/Suj5r1Sw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.5.tgz", - "integrity": "sha512-IJXjW13DY5UPsx/eG5DGfXtJ7Ydwrvw/BTZ2Y93lRLHzszVpSmeVmlxjZP5IW2afTSgMLaAAsqNw4NhppRGN8A==", - "cpu": [ - "x64" - ], + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.4.tgz", + "integrity": "sha512-2yopjelNkkCvIjUgBGhrn153IBPLwnsDeNiq6oA0WkeM8tGmQi4td+PGi9jAriUDAkc59Yoi2q9hYA6efiY7Zw==", "dev": true, - "optional": true, - "os": [ - "win32" - ], "engines": { "node": ">= 18" } @@ -1726,6 +1677,115 @@ } } }, + "node_modules/@nomicfoundation/hardhat-verify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.11.tgz", + "integrity": "sha512-lGIo4dNjVQFdsiEgZp3KP6ntLiF7xJEJsbNHfSyIiFCyI0Yv0518ElsFtMC5uCuHEChiBBMrib9jWQvHHT+X3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "lodash.clonedeep": "^4.5.0", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + }, + "peerDependencies": { + "hardhat": "^2.0.4" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@nomicfoundation/hardhat-verify/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@nomicfoundation/solidity-analyzer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", @@ -1917,108 +1977,6 @@ "hardhat": "^2.0.0" } }, - "node_modules/@nomiclabs/hardhat-etherscan": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz", - "integrity": "sha512-v5F6IzQhrsjHh6kQz4uNrym49brK9K5bYCq2zQZ729RYRaifI9hHbtmK+KkIVevfhut7huQFEQ77JLRMAzWYjQ==", - "deprecated": "The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead", - "dev": true, - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@ethersproject/address": "^5.0.2", - "cbor": "^8.1.0", - "chalk": "^2.4.2", - "debug": "^4.1.1", - "fs-extra": "^7.0.1", - "lodash": "^4.17.11", - "semver": "^6.3.0", - "table": "^6.8.0", - "undici": "^5.14.0" - }, - "peerDependencies": { - "hardhat": "^2.0.4" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@nomiclabs/hardhat-etherscan/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@nomiclabs/hardhat-waffle": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.6.tgz", @@ -3531,27 +3489,31 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", "dev": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chokidar/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/ci-info": { @@ -15071,14 +15033,14 @@ } }, "node_modules/hardhat": { - "version": "2.22.3", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.3.tgz", - "integrity": "sha512-k8JV2ECWNchD6ahkg2BR5wKVxY0OiKot7fuxiIpRK0frRqyOljcR2vKwgWSLw6YIeDcNNA4xybj7Og7NSxr2hA==", + "version": "2.22.15", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.15.tgz", + "integrity": "sha512-BpTGa9PE/sKAaHi4s/S1e9WGv63DR1m7Lzfd60C8gSEchDPfAJssVRSq0MZ2v2k76ig9m0kHAwVLf5teYwu/Mw==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.3.5", + "@nomicfoundation/edr": "^0.6.4", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -15091,7 +15053,7 @@ "ansi-escapes": "^4.3.0", "boxen": "^5.1.2", "chalk": "^2.4.2", - "chokidar": "^3.4.0", + "chokidar": "^4.0.0", "ci-info": "^2.0.0", "debug": "^4.1.1", "enquirer": "^2.3.0", @@ -15104,6 +15066,7 @@ "glob": "7.2.0", "immutable": "^4.0.0-rc.12", "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", "keccak": "^3.0.2", "lodash": "^4.17.11", "mnemonist": "^0.38.0", @@ -15112,7 +15075,7 @@ "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", - "solc": "0.7.3", + "solc": "0.8.26", "source-map-support": "^0.5.13", "stacktrace-parser": "^0.1.10", "tsort": "0.0.1", @@ -15236,6 +15199,15 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/hardhat/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/hardhat/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -15266,15 +15238,6 @@ "node": ">=4" } }, - "node_modules/hardhat/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, "node_modules/hardhat/node_modules/resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -15287,18 +15250,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hardhat/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/hardhat/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -15309,39 +15260,24 @@ } }, "node_modules/hardhat/node_modules/solc": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", - "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz", + "integrity": "sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==", "dev": true, "dependencies": { "command-exists": "^1.2.8", - "commander": "3.0.2", + "commander": "^8.1.0", "follow-redirects": "^1.12.1", - "fs-extra": "^0.30.0", "js-sha3": "0.8.0", "memorystream": "^0.3.1", - "require-from-string": "^2.0.0", "semver": "^5.5.0", "tmp": "0.0.33" }, "bin": { - "solcjs": "solcjs" + "solcjs": "solc.js" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" + "node": ">=10.0.0" } }, "node_modules/hardhat/node_modules/solc/node_modules/semver": { @@ -16162,6 +16098,15 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "engines": { + "node": ">=7.10.1" + } + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -16377,6 +16322,13 @@ "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", "dev": true }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/package.json b/package.json index 6933a56e..d74f2e0f 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,11 @@ "compile": "hardhat compile", "compile:force": "hardhat compile --force", "coverage": "hardhat coverage --testfiles './test/**/*.unit.test.ts'", - "fork:eth:mainnet": "hardhat node:fork eth_mainnet 8545", - "fork:eth:sepolia": "hardhat node:fork eth_sepolia 8545", - "fork:opt:sepolia": "hardhat node:fork opt_sepolia 9545", - "fork:opt:mainnet": "hardhat node:fork opt_mainnet 9545", - "deploy": "ts-node --files ./scripts/optimism/deploy-scratch.ts", - "deploy-new-steth-contracts": "ts-node --files ./scripts/optimism/deploy-new-steth-contracts.ts", + "fork:l1": "hardhat node:fork l1 8545", + "fork:l2": "hardhat node:fork l2 9545", + "deploy-bridge-without-notifier": "ts-node --files ./scripts/optimism/deploy-bridge-without-notifier.ts", + "deploy-bridge": "ts-node --files ./scripts/optimism/deploy-bridge.ts", + "deploy-steth": "ts-node --files ./scripts/optimism/deploy-steth.ts", "finalize-message": "ts-node --files ./scripts/optimism/finalize-message.ts", "test:e2e": "hardhat test ./test/e2e/*.e2e.test.ts", "test:managing-e2e": "hardhat test ./test/managing-e2e/*.e2e.test.ts", @@ -24,8 +23,8 @@ "author": "", "license": "ISC", "devDependencies": { + "@nomicfoundation/hardhat-verify": "^2.0.11", "@nomiclabs/hardhat-ethers": "^2.0.6", - "@nomiclabs/hardhat-etherscan": "^3.1.8", "@nomiclabs/hardhat-waffle": "^2.0.3", "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^2.3.1", @@ -46,7 +45,7 @@ "ethereum-waffle": "^3.4.4", "ethereumjs-util": "^7.0.8", "ethers": "^5.6.2", - "hardhat": "^2.12.2", + "hardhat": "^2.22.15", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.6.1", "prettier-plugin-solidity": "^1.0.0-beta.13", diff --git a/scripts/optimism/check-deposits-concurrent.ts b/scripts/optimism/check-deposits-concurrent.ts index 6c7b1bcf..33e2be30 100644 --- a/scripts/optimism/check-deposits-concurrent.ts +++ b/scripts/optimism/check-deposits-concurrent.ts @@ -4,12 +4,7 @@ import network from "../../utils/network"; import pLimit from "p-limit"; async function main() { - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); - - const [ethereumProvider, optimismProvider] = ethOptNetwork.getProviders({ - forking: env.forking() - }); + const [ethereumProvider, optimismProvider] = network.getProviders({ forking: env.forking() }); // Mainnet const ethBridgeAddress = process.env["L1_TOKEN_BRIDGE"] ?? "0x76943C0D61395d8F2edF9060e1533529cAe05dE6" diff --git a/scripts/optimism/cross-chain-relayer.ts b/scripts/optimism/cross-chain-relayer.ts index d3768059..0d521183 100644 --- a/scripts/optimism/cross-chain-relayer.ts +++ b/scripts/optimism/cross-chain-relayer.ts @@ -13,10 +13,8 @@ import { L2CrossDomainMessenger__factory } from "../../typechain"; async function main() { console.log("Run Relayer"); - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); - const [, optProvider] = ethOptNetwork.getProviders({ forking: true }); - const optAddresses = addresses(networkName); + const [, optProvider] = network.getProviders({ forking: true }); + const optAddresses = addresses(); const ethProviderUrl = 'ws://localhost:8545'; const wsEthProvider = new ethers.providers.WebSocketProvider(ethProviderUrl); @@ -34,7 +32,7 @@ async function main() { ); // 1. Catch Event - const optimismPortalAddress = networkName == "mainnet" ? "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed" : "0x16Fc5058F25648194471939df75CF27A2fdC48BC"; + const optimismPortalAddress = env.address("L1_L2_PORTAL", "0x16Fc5058F25648194471939df75CF27A2fdC48BC"); const l1MessngerAbi = [ "event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit)" diff --git a/scripts/optimism/deploy-bridge-without-notifier.ts b/scripts/optimism/deploy-bridge-without-notifier.ts new file mode 100644 index 00000000..ea90ee1e --- /dev/null +++ b/scripts/optimism/deploy-bridge-without-notifier.ts @@ -0,0 +1,136 @@ +import env from "../../utils/env"; +import prompt from "../../utils/prompt"; +import network from "../../utils/network"; +import deployment from "../../utils/deployment"; +import { BridgingManagement } from "../../utils/bridging-management"; +import deployAll from "../../utils/optimism/deployAll"; +import { TokenRateOracleManagement } from "../../utils/tokenRateOracle-management"; +import * as fs from 'fs'; + +async function main() { + + const [l1Deployer] = network.getSigners(env.privateKey(), { + forking: env.forking() + }); + + const [, l2Deployer] = network.getSigners( + env.string("L2_DEPLOYER_PRIVATE_KEY"), + { + forking: env.forking() + } + ); + + const deploymentConfig = deployment.loadMultiChainDeploymentConfig(); + + const [l1DeployScript, l2DeployScript] = await deployAll(false, { logger: console }) + .deployAllScript( + { + l1CrossDomainMessenger: deploymentConfig.l1.l1CrossDomainMessenger, + l1TokenNonRebasable: deploymentConfig.l1.l1TokenNonRebasable, + l1TokenRebasable: deploymentConfig.l1.l1RebasableToken, + accountingOracle: deploymentConfig.l1.accountingOracle, + l2GasLimitForPushingTokenRate: deploymentConfig.l1.l2GasLimitForPushingTokenRate, + + deployer: l1Deployer, + admins: { + proxy: deploymentConfig.l1.proxyAdmin, + bridge: l1Deployer.address, + }, + deployOffset: 0, + }, + { + l2CrossDomainMessenger: deploymentConfig.l2.l2CrossDomainMessenger, + tokenRateOracle: { + admin: l2Deployer.address, + tokenRateOutdatedDelay: deploymentConfig.l2.tokenRateOutdatedDelay, + maxAllowedL2ToL1ClockLag: deploymentConfig.l2.maxAllowedL2ToL1ClockLag, + maxAllowedTokenRateDeviationPerDayBp: deploymentConfig.l2.maxAllowedTokenRateDeviationPerDayBp, + oldestRateAllowedInPauseTimeSpan: deploymentConfig.l2.oldestRateAllowedInPauseTimeSpan, + minTimeBetweenTokenRateUpdates: deploymentConfig.l2.minTimeBetweenTokenRateUpdates, + tokenRate: deploymentConfig.l2.initialTokenRateValue, + l1Timestamp: deploymentConfig.l2.initialTokenRateL1Timestamp + }, + l2TokenNonRebasable: { + name: deploymentConfig.l2.l2TokenNonRebasableName, + symbol: deploymentConfig.l2.l2TokenNonRebasableSymbol, + version: deploymentConfig.l2.l2TokenNonRebasableDomainVersion + }, + l2TokenRebasable: { + name: deploymentConfig.l2.l2TokenRebasableName, + symbol: deploymentConfig.l2.l2TokenRebasableSymbol, + version: deploymentConfig.l2.l2TokenRebasableDomainVersion + }, + + deployer: l2Deployer, + admins: { + proxy: deploymentConfig.l2.proxyAdmin, + bridge: l2Deployer.address, + }, + deployOffset: 0, + } + ); + + await deployment.printMultiChainDeploymentConfig( + "Deploy Optimism Bridge", + l1Deployer, + l2Deployer, + deploymentConfig, + l1DeployScript, + l2DeployScript, + true + ); + + await prompt.proceed(); + + await l1DeployScript.run(); + await l2DeployScript.run(); + + const l1BridgingManagement = new BridgingManagement( + l1DeployScript.bridgeProxyAddress, + l1Deployer, + { logger: console } + ); + + const l2BridgingManagement = new BridgingManagement( + l2DeployScript.tokenBridgeProxyAddress, + l2Deployer, + { logger: console } + ); + + const tokenRateOracleManagement = new TokenRateOracleManagement( + l2DeployScript.tokenRateOracleProxyAddress, + l2Deployer, + { logger: console } + ); + + await l1BridgingManagement.setup(deploymentConfig.l1); + await l2BridgingManagement.setup(deploymentConfig.l2); + await tokenRateOracleManagement.setup({ + tokenRateOracleAdmin: deploymentConfig.l2.tokenRateOracleAdmin, + initialTokenRateValue: deploymentConfig.l2.initialTokenRateValue, + initialTokenRateL1Timestamp: deploymentConfig.l2.initialTokenRateL1Timestamp, + rateUpdatesEnabled: deploymentConfig.l2.tokenRateUpdateEnabled, + rateUpdatesDisablers: deploymentConfig.l2.tokenRateUpdateDisablers, + rateUpdatesEnablers: deploymentConfig.l2.tokenRateUpdateEnablers + }); + + await l1DeployScript.saveResultToFile("l1DeployArgs.json"); + await l2DeployScript.saveResultToFile("l2DeployArgs.json"); + + const deployResult = JSON.stringify({ + ethereum: l1DeployScript, + optimism: l2DeployScript + }, null, 2); + + const fileName = 'deployResult.json'; + try { + fs.writeFileSync(fileName, `${deployResult}\n`, { encoding: "utf8", flag: "w" }); + } catch (error) { + throw new Error(`Failed to write network state file ${fileName}: ${(error as Error).message}`); + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/optimism/deploy-bridge.ts b/scripts/optimism/deploy-bridge.ts new file mode 100644 index 00000000..63dc4714 --- /dev/null +++ b/scripts/optimism/deploy-bridge.ts @@ -0,0 +1,130 @@ +import env from "../../utils/env"; +import prompt from "../../utils/prompt"; +import network from "../../utils/network"; +import deployment from "../../utils/deployment"; +import { BridgingManagement } from "../../utils/bridging-management"; +import deployAll from "../../utils/optimism/deployAll"; +import { TokenRateNotifierManagement } from "../../utils/tokenRateNotifier-management"; + +async function main() { + + const [l1Deployer] = network.getSigners(env.privateKey(), { + forking: env.forking() + }); + + const [l1Provider] = network.getProviders({ + forking: env.forking() + }); + + const [, l2Deployer] = network.getSigners( + env.string("L2_DEPLOYER_PRIVATE_KEY"), + { + forking: env.forking() + } + ); + + const deploymentConfig = deployment.loadMultiChainScratchDeploymentConfig(); + + const [l1DeployScript, l2DeployScript] = await deployAll(true, { logger: console }) + .deployAllScript( + { + lido: deploymentConfig.l1.lido, + tokenRateNotifierOwner: deploymentConfig.l1.tokenRateNotifierOwner, + + l1CrossDomainMessenger: deploymentConfig.l1.l1CrossDomainMessenger, + l1TokenNonRebasable: deploymentConfig.l1.l1TokenNonRebasable, + l1TokenRebasable: deploymentConfig.l1.l1RebasableToken, + accountingOracle: deploymentConfig.l1.accountingOracle, + l2GasLimitForPushingTokenRate: deploymentConfig.l1.l2GasLimitForPushingTokenRate, + + deployer: l1Deployer, + admins: { + proxy: deploymentConfig.l1.proxyAdmin, + bridge: l1Deployer.address, + }, + deployOffset: 0, + }, + { + l2CrossDomainMessenger: deploymentConfig.l2.l2CrossDomainMessenger, + + tokenRateOracle: { + admin: l2Deployer.address, + tokenRateOutdatedDelay: deploymentConfig.l2.tokenRateOutdatedDelay, + maxAllowedL2ToL1ClockLag: deploymentConfig.l2.maxAllowedL2ToL1ClockLag, + maxAllowedTokenRateDeviationPerDayBp: deploymentConfig.l2.maxAllowedTokenRateDeviationPerDayBp, + oldestRateAllowedInPauseTimeSpan: deploymentConfig.l2.oldestRateAllowedInPauseTimeSpan, + minTimeBetweenTokenRateUpdates: deploymentConfig.l2.minTimeBetweenTokenRateUpdates, + tokenRate: deploymentConfig.l2.initialTokenRateValue, + l1Timestamp: deploymentConfig.l2.initialTokenRateL1Timestamp + }, + l2TokenNonRebasable: { + name: deploymentConfig.l2.l2TokenNonRebasableName, + symbol: deploymentConfig.l2.l2TokenNonRebasableSymbol, + version: deploymentConfig.l2.l2TokenNonRebasableDomainVersion + }, + l2TokenRebasable: { + name: deploymentConfig.l2.l2TokenRebasableName, + symbol: deploymentConfig.l2.l2TokenRebasableSymbol, + version: deploymentConfig.l2.l2TokenRebasableDomainVersion + }, + + deployer: l2Deployer, + admins: { + proxy: deploymentConfig.l2.proxyAdmin, + bridge: l2Deployer.address, + }, + deployOffset: 0, + } + ); + + await deployment.printMultiChainDeploymentConfig( + "Deploy Optimism Bridge", + l1Deployer, + l2Deployer, + deploymentConfig, + l1DeployScript, + l2DeployScript, + true + ); + + await prompt.proceed(); + + await l1DeployScript.run(); + await l2DeployScript.run(); + + if (!l1DeployScript.tokenRateNotifierImplAddress || !l1DeployScript.opStackTokenRatePusherImplAddress) { + throw new Error('Token rate notifier addresses are not defined'); + } + + const tokenRateNotifierManagement = new TokenRateNotifierManagement( + l1DeployScript.tokenRateNotifierImplAddress, + l1Deployer + ); + await tokenRateNotifierManagement.setup({ + tokenRateNotifier: l1DeployScript.tokenRateNotifierImplAddress, + opStackTokenRatePusher: l1DeployScript.opStackTokenRatePusherImplAddress, + ethDeployer: l1Deployer, + ethProvider: l1Provider, + notifierOwner: deploymentConfig.l1.lido + }); + + const l1BridgingManagement = new BridgingManagement( + l1DeployScript.bridgeProxyAddress, + l1Deployer, + { logger: console } + ); + + const l2BridgingManagement = new BridgingManagement( + l2DeployScript.tokenBridgeProxyAddress, + l2Deployer, + { logger: console } + ); + + await l1BridgingManagement.setup(deploymentConfig.l1); + await l2BridgingManagement.setup(deploymentConfig.l2); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/optimism/deploy-new-steth-contracts.ts b/scripts/optimism/deploy-new-steth-contracts.ts deleted file mode 100644 index a61224c8..00000000 --- a/scripts/optimism/deploy-new-steth-contracts.ts +++ /dev/null @@ -1,129 +0,0 @@ -import env from "../../utils/env"; -import prompt from "../../utils/prompt"; -import network from "../../utils/network"; -import deployment from "../../utils/deployment"; -import { TokenRateNotifierManagement } from "../../utils/tokenRateNotifier-management"; -import { TokenRateOracleManagement } from "../../utils/tokenRateOracle-management"; -import deploy from "../../utils/optimism/deploymentStETH"; - -async function main() { - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); - - const [ethDeployer] = ethOptNetwork.getSigners(env.privateKey(), { - forking: env.forking(), - }); - const [ethProvider] = ethOptNetwork.getProviders({ - forking: env.forking() - }); - - const [, optDeployer] = ethOptNetwork.getSigners( - env.string("OPT_DEPLOYER_PRIVATE_KEY"), - { - forking: env.forking(), - } - ); - - const deploymentConfig = deployment.loadMultiChainDeploymentConfig(); - - const [l1DeployScript, l2DeployScript] = await deploy(networkName, { logger: console }) - .deployScript( - { - l1TokenNonRebasable: deploymentConfig.ethereum.l1TokenNonRebasable, - l1TokenRebasable: deploymentConfig.ethereum.l1RebasableToken, - accountingOracle: deploymentConfig.ethereum.accountingOracle, - l2GasLimitForPushingTokenRate: deploymentConfig.ethereum.l2GasLimitForPushingTokenRate, - l1TokenBridge: deploymentConfig.ethereum.l1TokenBridge, - lido: deploymentConfig.ethereum.lido, - - deployer: ethDeployer, - admins: { - proxy: deploymentConfig.ethereum.bridgeProxyAdmin, - bridge: ethDeployer.address - }, - deployOffset: 0, - }, - { - tokenRateOracle: { - proxyAdmin: deploymentConfig.optimism.tokenRateOracleProxyAdmin, - admin: optDeployer.address, - constructor: { - tokenRateOutdatedDelay: deploymentConfig.optimism.tokenRateOutdatedDelay, - maxAllowedL2ToL1ClockLag: deploymentConfig.optimism.maxAllowedL2ToL1ClockLag, - maxAllowedTokenRateDeviationPerDayBp: deploymentConfig.optimism.maxAllowedTokenRateDeviationPerDayBp, - oldestRateAllowedInPauseTimeSpan: deploymentConfig.optimism.oldestRateAllowedInPauseTimeSpan, - minTimeBetweenTokenRateUpdates: deploymentConfig.optimism.minTimeBetweenTokenRateUpdates - }, - initialize: { - tokenRate: deploymentConfig.optimism.initialTokenRateValue, - l1Timestamp: deploymentConfig.optimism.initialTokenRateL1Timestamp - } - }, - l2TokenBridge: deploymentConfig.optimism.l2TokenBridge, - l2TokenNonRebasable: { - address: deploymentConfig.optimism.l2TokenNonRebasableAddress, - version: deploymentConfig.optimism.l2TokenNonRebasableDomainVersion - }, - l2TokenRebasable: { - proxyAdmin: deploymentConfig.optimism.l2TokenRebasableProxyAdmin, - version: deploymentConfig.optimism.l2TokenRebasableDomainVersion - }, - - deployer: optDeployer, - admins: { - proxy: deploymentConfig.optimism.bridgeProxyAdmin, - bridge: optDeployer.address, - }, - deployOffset: 0, - } - ); - - await deployment.printMultiChainDeploymentConfig( - "Deploy new contracts for Optimism Bridge", - ethDeployer, - optDeployer, - deploymentConfig, - l1DeployScript, - l2DeployScript, - false - ); - - await prompt.proceed(); - - await l1DeployScript.run(); - await l2DeployScript.run(); - - /// Setup TokenRateNotifier - const tokenRateNotifierManagement = new TokenRateNotifierManagement( - l1DeployScript.tokenRateNotifierImplAddress, - ethDeployer, - { logger: console } - ); - await tokenRateNotifierManagement.setup({ - tokenRateNotifier: l1DeployScript.tokenRateNotifierImplAddress, - opStackTokenRatePusher: l1DeployScript.opStackTokenRatePusherImplAddress, - ethDeployer: ethDeployer, - ethProvider: ethProvider, - notifierOwner: deploymentConfig.ethereum.tokenRateNotifierOwner - }); - - /// Setup TokenRateOracle - const tokenRateOracleManagement = new TokenRateOracleManagement( - l2DeployScript.tokenRateOracleProxyAddress, - optDeployer, - { logger: console } - ); - await tokenRateOracleManagement.setup({ - tokenRateOracleAdmin: deploymentConfig.optimism.tokenRateOracleAdmin, - initialTokenRateValue: deploymentConfig.optimism.initialTokenRateValue, - initialTokenRateL1Timestamp: deploymentConfig.optimism.initialTokenRateL1Timestamp, - rateUpdatesEnabled: deploymentConfig.optimism.tokenRateUpdateEnabled, - rateUpdatesDisablers: deploymentConfig.optimism.tokenRateUpdateDisablers, - rateUpdatesEnablers: deploymentConfig.optimism.tokenRateUpdateEnablers - }); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/optimism/deploy-scratch.ts b/scripts/optimism/deploy-scratch.ts deleted file mode 100644 index 5e38d22b..00000000 --- a/scripts/optimism/deploy-scratch.ts +++ /dev/null @@ -1,118 +0,0 @@ -import env from "../../utils/env"; -import prompt from "../../utils/prompt"; -import network from "../../utils/network"; -import deployment from "../../utils/deployment"; -import { BridgingManagement } from "../../utils/bridging-management"; -import deploymentAll from "../../utils/optimism/deployment"; -import { TokenRateNotifierManagement } from "../../utils/tokenRateNotifier-management"; - -async function main() { - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); - - const [ethDeployer] = ethOptNetwork.getSigners(env.privateKey(), { - forking: env.forking() - }); - - const [ethProvider] = ethOptNetwork.getProviders({ - forking: env.forking() - }); - - const [, optDeployer] = ethOptNetwork.getSigners( - env.string("OPT_DEPLOYER_PRIVATE_KEY"), - { - forking: env.forking() - } - ); - - const deploymentConfig = deployment.loadMultiChainDeploymentConfig(); - - const [l1DeployScript, l2DeployScript] = await deploymentAll(networkName, { logger: console }) - .deployAllScript( - { - l1TokenNonRebasable: deploymentConfig.ethereum.l1TokenNonRebasable, - l1TokenRebasable: deploymentConfig.ethereum.l1RebasableToken, - accountingOracle: deploymentConfig.ethereum.accountingOracle, - l2GasLimitForPushingTokenRate: deploymentConfig.ethereum.l2GasLimitForPushingTokenRate, - lido: deploymentConfig.ethereum.lido, - - deployer: ethDeployer, - admins: { - proxy: deploymentConfig.ethereum.bridgeProxyAdmin, - bridge: ethDeployer.address - }, - deployOffset: 0, - }, - { - tokenRateOracle: { - tokenRateOutdatedDelay: deploymentConfig.optimism.tokenRateOutdatedDelay, - maxAllowedL2ToL1ClockLag: deploymentConfig.optimism.maxAllowedL2ToL1ClockLag, - maxAllowedTokenRateDeviationPerDayBp: deploymentConfig.optimism.maxAllowedTokenRateDeviationPerDayBp, - oldestRateAllowedInPauseTimeSpan: deploymentConfig.optimism.oldestRateAllowedInPauseTimeSpan, - minTimeBetweenTokenRateUpdates: deploymentConfig.optimism.minTimeBetweenTokenRateUpdates, - tokenRate: deploymentConfig.optimism.initialTokenRateValue, - l1Timestamp: deploymentConfig.optimism.initialTokenRateL1Timestamp - }, - l2TokenNonRebasable: { - version: deploymentConfig.optimism.l2TokenNonRebasableDomainVersion - }, - l2TokenRebasable: { - version: deploymentConfig.optimism.l2TokenRebasableDomainVersion - }, - - deployer: optDeployer, - admins: { - proxy: deploymentConfig.optimism.bridgeProxyAdmin, - bridge: optDeployer.address, - }, - deployOffset: 0, - } - ); - - await deployment.printMultiChainDeploymentConfig( - "Deploy Optimism Bridge", - ethDeployer, - optDeployer, - deploymentConfig, - l1DeployScript, - l2DeployScript, - true - ); - - await prompt.proceed(); - - await l1DeployScript.run(); - await l2DeployScript.run(); - - const tokenRateNotifierManagement = new TokenRateNotifierManagement( - l1DeployScript.tokenRateNotifierImplAddress, - ethDeployer - ); - await tokenRateNotifierManagement.setup({ - tokenRateNotifier: l1DeployScript.tokenRateNotifierImplAddress, - opStackTokenRatePusher: l1DeployScript.opStackTokenRatePusherImplAddress, - ethDeployer: ethDeployer, - ethProvider: ethProvider, - notifierOwner: deploymentConfig.ethereum.tokenRateNotifierOwner - }); - - const l1BridgingManagement = new BridgingManagement( - l1DeployScript.bridgeProxyAddress, - ethDeployer, - { logger: console } - ); - - const l2BridgingManagement = new BridgingManagement( - l2DeployScript.tokenBridgeProxyAddress, - optDeployer, - { logger: console } - ); - - await l1BridgingManagement.setup(deploymentConfig.ethereum); - await l2BridgingManagement.setup(deploymentConfig.optimism); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/scripts/optimism/deploy-steth.ts b/scripts/optimism/deploy-steth.ts new file mode 100644 index 00000000..699b8885 --- /dev/null +++ b/scripts/optimism/deploy-steth.ts @@ -0,0 +1,131 @@ +import env from "../../utils/env"; +import prompt from "../../utils/prompt"; +import network from "../../utils/network"; +import deployment from "../../utils/deployment"; +import { TokenRateNotifierManagement } from "../../utils/tokenRateNotifier-management"; +import { TokenRateOracleManagement } from "../../utils/tokenRateOracle-management"; +import deployStETH from "../../utils/optimism/deployStETH"; + +async function main() { + + const [l1Deployer] = network.getSigners(env.privateKey(), { + forking: env.forking(), + }); + const [ethProvider] = network.getProviders({ + forking: env.forking() + }); + + const [, l2Deployer] = network.getSigners( + env.string("L2_DEPLOYER_PRIVATE_KEY"), + { + forking: env.forking(), + } + ); + + const deploymentConfig = deployment.loadMultiChainStETHDeploymentConfig(); + + const [l1DeployScript, l2DeployScript] = await deployStETH({ logger: console }) + .deployScript( + { + l1CrossDomainMessenger: deploymentConfig.l1.l1CrossDomainMessenger, + l1TokenNonRebasable: deploymentConfig.l1.l1TokenNonRebasable, + l1TokenRebasable: deploymentConfig.l1.l1RebasableToken, + accountingOracle: deploymentConfig.l1.accountingOracle, + l2GasLimitForPushingTokenRate: deploymentConfig.l1.l2GasLimitForPushingTokenRate, + + l1TokenBridge: deploymentConfig.l1.l1TokenBridge, + lido: deploymentConfig.l1.lido, + tokenRateNotifierOwner: l1Deployer.address, + + deployer: l1Deployer, + admins: { + proxy: deploymentConfig.l1.proxyAdmin, + bridge: l1Deployer.address + }, + deployOffset: 0, + }, + { + l2CrossDomainMessenger: deploymentConfig.l2.l2CrossDomainMessenger, + l2TokenBridge: deploymentConfig.l2.l2TokenBridge, + + tokenRateOracle: { + admin: l2Deployer.address, + tokenRateOutdatedDelay: deploymentConfig.l2.tokenRateOutdatedDelay, + maxAllowedL2ToL1ClockLag: deploymentConfig.l2.maxAllowedL2ToL1ClockLag, + maxAllowedTokenRateDeviationPerDayBp: deploymentConfig.l2.maxAllowedTokenRateDeviationPerDayBp, + oldestRateAllowedInPauseTimeSpan: deploymentConfig.l2.oldestRateAllowedInPauseTimeSpan, + minTimeBetweenTokenRateUpdates: deploymentConfig.l2.minTimeBetweenTokenRateUpdates, + tokenRate: deploymentConfig.l2.initialTokenRateValue, + l1Timestamp: deploymentConfig.l2.initialTokenRateL1Timestamp + }, + l2TokenNonRebasable: { + address: deploymentConfig.l2.l2TokenNonRebasable, + name: deploymentConfig.l2.l2TokenNonRebasableName, + symbol: deploymentConfig.l2.l2TokenRebasableSymbol, + version: deploymentConfig.l2.l2TokenNonRebasableDomainVersion + }, + l2TokenRebasable: { + proxyAdmin: deploymentConfig.l2.proxyAdmin, + name: deploymentConfig.l2.l2TokenRebasableName, + symbol: deploymentConfig.l2.l2TokenRebasableSymbol, + version: deploymentConfig.l2.l2TokenRebasableDomainVersion + }, + + deployer: l2Deployer, + admins: { + proxy: deploymentConfig.l2.proxyAdmin, + bridge: l2Deployer.address, + }, + deployOffset: 0, + } + ); + + await deployment.printMultiChainDeploymentConfig( + "Deploy new contracts for Optimism Bridge", + l1Deployer, + l2Deployer, + deploymentConfig, + l1DeployScript, + l2DeployScript, + false + ); + + await prompt.proceed(); + + await l1DeployScript.run(); + await l2DeployScript.run(); + + /// Setup TokenRateNotifier + const tokenRateNotifierManagement = new TokenRateNotifierManagement( + l1DeployScript.tokenRateNotifierImplAddress, + l1Deployer, + { logger: console } + ); + await tokenRateNotifierManagement.setup({ + tokenRateNotifier: l1DeployScript.tokenRateNotifierImplAddress, + opStackTokenRatePusher: l1DeployScript.opStackTokenRatePusherImplAddress, + ethDeployer: l1Deployer, + ethProvider: ethProvider, + notifierOwner: deploymentConfig.l1.tokenRateNotifierOwner + }); + + /// Setup TokenRateOracle + const tokenRateOracleManagement = new TokenRateOracleManagement( + l2DeployScript.tokenRateOracleProxyAddress, + l2Deployer, + { logger: console } + ); + await tokenRateOracleManagement.setup({ + tokenRateOracleAdmin: deploymentConfig.l2.tokenRateOracleAdmin, + initialTokenRateValue: deploymentConfig.l2.initialTokenRateValue, + initialTokenRateL1Timestamp: deploymentConfig.l2.initialTokenRateL1Timestamp, + rateUpdatesEnabled: deploymentConfig.l2.tokenRateUpdateEnabled, + rateUpdatesDisablers: deploymentConfig.l2.tokenRateUpdateDisablers, + rateUpdatesEnablers: deploymentConfig.l2.tokenRateUpdateEnablers + }); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/optimism/execute-gov-bridge-executor.ts b/scripts/optimism/execute-gov-bridge-executor.ts index a9634813..ff0ddf60 100644 --- a/scripts/optimism/execute-gov-bridge-executor.ts +++ b/scripts/optimism/execute-gov-bridge-executor.ts @@ -6,12 +6,10 @@ import testing from "../../utils/testing"; async function main() { const isForking = true; - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); const GOV_BRIDGE_EXECUTOR = testing.env.OPT_GOV_BRIDGE_EXECUTOR(); - const [, optRunner] = ethOptNetwork.getSigners(env.privateKey(), { + const [, optRunner] = network.getSigners(env.privateKey(), { forking: isForking, }); diff --git a/scripts/optimism/finalize-message.ts b/scripts/optimism/finalize-message.ts index ac6c9b5b..f9121c9d 100644 --- a/scripts/optimism/finalize-message.ts +++ b/scripts/optimism/finalize-message.ts @@ -3,16 +3,14 @@ import env from "../../utils/env"; import network from "../../utils/network"; async function main() { - const networkName = env.network(); const [l1Signer, l2Signer] = network - .multichain(["eth", "opt"], networkName) .getSigners(env.privateKey(), { forking: false }); const txHash = env.string("TX_HASH"); const crossDomainMessenger = new CrossChainMessenger({ - l1ChainId: network.chainId("eth", networkName), - l2ChainId: network.chainId("opt", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Signer, }); diff --git a/scripts/optimism/prove-message.ts b/scripts/optimism/prove-message.ts index e0c2ee5e..e7563e31 100644 --- a/scripts/optimism/prove-message.ts +++ b/scripts/optimism/prove-message.ts @@ -3,16 +3,14 @@ import env from "../../utils/env"; import network from "../../utils/network"; async function main() { - const networkName = env.network(); const [l1Signer, l2Signer] = network - .multichain(["eth", "opt"], networkName) .getSigners(env.privateKey(), { forking: false }); const txHash = env.string("TX_HASH"); const crossChainMessenger = new CrossChainMessenger({ - l1ChainId: network.chainId("eth", networkName), - l2ChainId: network.chainId("opt", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Signer, bedrock: true, diff --git a/scripts/optimism/update-ethereum-executor.ts b/scripts/optimism/update-ethereum-executor.ts deleted file mode 100644 index aec4314b..00000000 --- a/scripts/optimism/update-ethereum-executor.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { assert } from "chai"; -import { ethers } from "hardhat"; -import { GovBridgeExecutor__factory } from "../../typechain"; -import env from "../../utils/env"; -import lido from "../../utils/lido"; -import network from "../../utils/network"; -import optimism from "../../utils/optimism"; -import prompt from "../../utils/prompt"; - -// Set address of the bridge executor to run the script -const GOV_BRIDGE_EXECUTOR = ""; - -async function main() { - const isForking = env.forking(); - const networkName = env.network(); - const ethOptNetwork = network.multichain(["eth", "opt"], networkName); - - const [l1LDOHolder] = ethOptNetwork.getSigners( - env.string("TESTING_OPT_LDO_HOLDER_PRIVATE_KEY"), - { forking: isForking } - ); - const [, optRunner] = ethOptNetwork.getSigners(env.privateKey(), { - forking: isForking, - }); - - const govBridgeExecutor = GovBridgeExecutor__factory.connect( - GOV_BRIDGE_EXECUTOR, - optRunner - ); - - const newEthExecutorLidoDAO = lido(networkName, l1LDOHolder); - const oldEthExecutorLidoDAO = lido( - networkName === "mainnet" ? "mainnet_test" : networkName, - l1LDOHolder - ); - const prevEthGovExecutorAddress = - await govBridgeExecutor.getEthereumGovernanceExecutor(); - - assert.equal( - oldEthExecutorLidoDAO.agent.address.toLocaleLowerCase(), - prevEthGovExecutorAddress.toLowerCase(), - `${oldEthExecutorLidoDAO.agent.address} is not current ethereumGovernanceExecutor` - ); - - console.log(` · Is forking: ${isForking}`); - console.log(` · Network Name: ${networkName}`); - console.log( - ` · Prev Ethereum Governance Executor: ${prevEthGovExecutorAddress}` - ); - console.log( - ` · New Ethereum Governance Executor: ${newEthExecutorLidoDAO.agent.address}` - ); - console.log(` · LDO Holder: ${l1LDOHolder.address}`); - console.log(` · LDO Holder ETH balance: ${await l1LDOHolder.getBalance()}`); - console.log(` · L2 tx runner: ${optRunner.address}`); - console.log(` · L2 tx runner ETH balance: ${await optRunner.getBalance()}`); - - await prompt.proceed(); - - console.log(`Preparing the voting tx...`); - - const optAddresses = optimism.addresses(networkName); - - // Prepare data for Governance Bridge Executor - const executorCalldata = await govBridgeExecutor.interface.encodeFunctionData( - "queue", - [ - [GOV_BRIDGE_EXECUTOR], - [0], - ["updateEthereumGovernanceExecutor(address)"], - [ - ethers.utils.defaultAbiCoder.encode( - ["address"], - [newEthExecutorLidoDAO.agent.address] - ), - ], - [false], - ] - ); - - const { callvalue, calldata } = await optimism - .messaging(networkName, { forking: isForking }) - .prepareL2Message({ - calldata: executorCalldata, - recipient: GOV_BRIDGE_EXECUTOR, - sender: oldEthExecutorLidoDAO.agent.address, - }); - - const createVoteTx = await oldEthExecutorLidoDAO.createVote( - l1LDOHolder, - "Update ethereumGovernanceExecutor on Optimism Governance Bridge Executor", - { - address: oldEthExecutorLidoDAO.agent.address, - signature: "execute(address,uint256,bytes)", - decodedCallData: [ - optAddresses.L1CrossDomainMessenger, - callvalue, - calldata, - ], - } - ); - - console.log("Creating voting to update ethereumGovernanceExecutor..."); - await createVoteTx.wait(); - console.log(`Vote was created!`); - - const votesCount = await oldEthExecutorLidoDAO.voting.votesLength(); - const voteId = votesCount.sub(1); - - console.log(`New vote id ${voteId.toString()}`); - console.log(`Voting for and executing the vote...`); - - const voteAndExecuteTx = await oldEthExecutorLidoDAO.voteAndExecute( - l1LDOHolder, - voteId, - true - ); - const executeTxReceipt = await voteAndExecuteTx.wait(); - - console.log(`Vote ${voteId.toString()} was executed!`); - - console.log(`Waiting for L2 transaction...`); - await optimism - .messaging(networkName, { forking: isForking }) - .waitForL2Message(executeTxReceipt.transactionHash); - - console.log(`Message delivered to L2`); - - console.log("Executing the queued task..."); - // execute task on L2 - const tasksCount = await govBridgeExecutor.getActionsSetCount(); - const targetTaskId = tasksCount.toNumber() - 1; - - const tx = await govBridgeExecutor.execute(targetTaskId); - await tx.wait(); - console.log(`Task executed on L2!`); - - const ethereumGovernanceExecutor = - await govBridgeExecutor.getEthereumGovernanceExecutor(); - - console.log( - `New ethereum governance executor is: ${ethereumGovernanceExecutor}` - ); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/test/e2e/bridging-rebasable-to.e2e.test.ts b/test/e2e/bridging-rebasable-to.e2e.test.ts index 9652dc00..b7ab41a2 100644 --- a/test/e2e/bridging-rebasable-to.e2e.test.ts +++ b/test/e2e/bridging-rebasable-to.e2e.test.ts @@ -4,8 +4,6 @@ import { } from "@eth-optimism/sdk"; import { assert } from "chai"; import { TransactionResponse } from "@ethersproject/providers"; - - import env from "../../utils/env"; import { wei } from "../../utils/wei"; import network from "../../utils/network"; import optimism from "../../utils/optimism"; @@ -88,8 +86,7 @@ import { .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "sepolia"); - const testingSetup = await optimism.testing(networkName).getE2ETestSetup(); + const testingSetup = await optimism.testing().getE2ETestSetup(); return { depositAmount: wei`0.0001 ether`, @@ -101,8 +98,8 @@ import { l1LidoTokensBridge: testingSetup.l1LidoTokensBridge, l2ERC20ExtendedTokensBridge: testingSetup.l2ERC20ExtendedTokensBridge, crossChainMessenger: new CrossChainMessenger({ - l2ChainId: network.chainId("opt", networkName), - l1ChainId: network.chainId("eth", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: testingSetup.l1Tester, l2SignerOrProvider: testingSetup.l2Tester, bridges: { diff --git a/test/e2e/bridging-rebasable.e2e.test.ts b/test/e2e/bridging-rebasable.e2e.test.ts index 173b90b5..e13d220b 100644 --- a/test/e2e/bridging-rebasable.e2e.test.ts +++ b/test/e2e/bridging-rebasable.e2e.test.ts @@ -4,8 +4,6 @@ import { } from "@eth-optimism/sdk"; import { assert } from "chai"; import { TransactionResponse } from "@ethersproject/providers"; - - import env from "../../utils/env"; import { wei } from "../../utils/wei"; import network from "../../utils/network"; import optimism from "../../utils/optimism"; @@ -78,8 +76,7 @@ import { .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "sepolia"); - const testingSetup = await optimism.testing(networkName).getE2ETestSetup(); + const testingSetup = await optimism.testing().getE2ETestSetup(); return { depositAmount: wei`0.0001 ether`, @@ -89,8 +86,8 @@ import { l2TokenRebasable: testingSetup.l2TokenRebasable, l1LidoTokensBridge: testingSetup.l1LidoTokensBridge, crossChainMessenger: new CrossChainMessenger({ - l2ChainId: network.chainId("opt", networkName), - l1ChainId: network.chainId("eth", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: testingSetup.l1Tester, l2SignerOrProvider: testingSetup.l2Tester, bridges: { diff --git a/test/e2e/bridging-to.e2e.test.ts b/test/e2e/bridging-to.e2e.test.ts index 72820b82..d4ed140e 100644 --- a/test/e2e/bridging-to.e2e.test.ts +++ b/test/e2e/bridging-to.e2e.test.ts @@ -1,13 +1,11 @@ import { CrossChainMessenger, - DAIBridgeAdapter, MessageStatus, } from "@eth-optimism/sdk"; import { assert } from "chai"; import { TransactionResponse } from "@ethersproject/providers"; import { LidoBridgeAdapter } from "../../utils/optimism/LidoBridgeAdapter"; -import env from "../../utils/env"; import { wei } from "../../utils/wei"; import network from "../../utils/network"; import optimism from "../../utils/optimism"; @@ -90,8 +88,7 @@ scenario("Optimism :: Bridging non-rebasable via depositTo/withdrawTo E2E test", .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "sepolia"); - const testingSetup = await optimism.testing(networkName).getE2ETestSetup(); + const testingSetup = await optimism.testing().getE2ETestSetup(); return { depositAmount: wei`0.0001 ether`, @@ -103,8 +100,8 @@ async function ctxFactory() { l1LidoTokensBridge: testingSetup.l1LidoTokensBridge, l2ERC20ExtendedTokensBridge: testingSetup.l2ERC20ExtendedTokensBridge, crossChainMessenger: new CrossChainMessenger({ - l2ChainId: network.chainId("opt", networkName), - l1ChainId: network.chainId("eth", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: testingSetup.l1Tester, l2SignerOrProvider: testingSetup.l2Tester, bridges: { diff --git a/test/e2e/bridging.e2e.test.ts b/test/e2e/bridging.e2e.test.ts index c3829e42..292424b8 100644 --- a/test/e2e/bridging.e2e.test.ts +++ b/test/e2e/bridging.e2e.test.ts @@ -5,7 +5,6 @@ import { import { assert } from "chai"; import { TransactionResponse } from "@ethersproject/providers"; import chalk from "chalk"; -import env from "../../utils/env"; import { wei } from "../../utils/wei"; import network from "../../utils/network"; import optimism from "../../utils/optimism"; @@ -77,8 +76,7 @@ scenario("Optimism :: Bridging non-rebasable token via deposit/withdraw E2E test .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "sepolia"); - const testingSetup = await optimism.testing(networkName).getE2ETestSetup(); + const testingSetup = await optimism.testing().getE2ETestSetup(); return { depositAmount: wei`0.0001 ether`, @@ -88,8 +86,8 @@ async function ctxFactory() { l2Token: testingSetup.l2Token, l1LidoTokensBridge: testingSetup.l1LidoTokensBridge, crossChainMessenger: new CrossChainMessenger({ - l2ChainId: network.chainId("opt", networkName), - l1ChainId: network.chainId("eth", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: testingSetup.l1Tester, l2SignerOrProvider: testingSetup.l2Tester, bridges: { diff --git a/test/e2e/pushingTokenRate.e2e.test.ts b/test/e2e/pushingTokenRate.e2e.test.ts index fa4495f5..e03e7abc 100644 --- a/test/e2e/pushingTokenRate.e2e.test.ts +++ b/test/e2e/pushingTokenRate.e2e.test.ts @@ -1,5 +1,4 @@ import { assert } from "chai"; -import env from "../../utils/env"; import network, { SignerOrProvider } from "../../utils/network"; import testingUtils, { scenario } from "../../utils/testing"; import { BigNumber } from 'ethers' @@ -50,16 +49,9 @@ async function ctxFactory() { async function getE2ETestSetup() { const testerPrivateKey = testingUtils.env.TESTING_PRIVATE_KEY(); - const networkName = env.network("TESTING_OPT_NETWORK", "sepolia"); - const ethOptNetworks = network.multichain(["eth", "opt"], networkName); - - const [ethProvider, optProvider] = ethOptNetworks.getProviders({ - forking: false, - }); - const [l1Tester, l2Tester] = ethOptNetworks.getSigners(testerPrivateKey, { - forking: false, - }); + const [ethProvider, optProvider] = network.getProviders({ forking: false }); + const [l1Tester, l2Tester] = network.getSigners(testerPrivateKey, { forking: false }); const contracts = await loadDeployedContracts(l1Tester, l2Tester); return { diff --git a/test/integration/_bridging-non-rebasable.ts b/test/integration/_bridging-non-rebasable.ts index e1a4dc4d..fd54dcc8 100644 --- a/test/integration/_bridging-non-rebasable.ts +++ b/test/integration/_bridging-non-rebasable.ts @@ -1,6 +1,5 @@ import { assert } from "chai"; import { BigNumber } from 'ethers' -import env from "../../utils/env"; import { wei } from "../../utils/wei"; import optimism from "../../utils/optimism"; import testing from "../../utils/testing"; @@ -543,7 +542,6 @@ export function ctxFactory(options: { withdrawalAmount, } = options; - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); const tokenRateDecimals = BigNumber.from(27); const { @@ -554,14 +552,14 @@ export function ctxFactory(options: { l1ERC20ExtendedTokensBridgeAdmin, l2ERC20ExtendedTokensBridgeAdmin, ...contracts - } = await optimism.testing(networkName).getIntegrationTestSetup(); + } = await optimism.testing().getIntegrationTestSetup(); const l1Snapshot = await l1Provider.send("evm_snapshot", []); const l2Snapshot = await l2Provider.send("evm_snapshot", []); const tokenRate = await contracts.l1Token.getStETHByWstETH(BigNumber.from(10).pow(tokenRateDecimals)); - await optimism.testing(networkName).stubL1CrossChainMessengerContract(); + await optimism.testing().stubL1CrossChainMessengerContract(); const accountA = testing.accounts.accountA(l1Provider, l2Provider); const accountB = testing.accounts.accountB(l1Provider, l2Provider); diff --git a/test/integration/_launch.test.ts b/test/integration/_launch.test.ts index 13b63f89..840b91df 100644 --- a/test/integration/_launch.test.ts +++ b/test/integration/_launch.test.ts @@ -6,7 +6,6 @@ import optimism from "../../utils/optimism"; import testing, { scenario } from "../../utils/testing"; import { BridgingManagerRole } from "../../utils/bridging-management"; import { L1LidoTokensBridge__factory } from "../../typechain"; -import { BigNumber } from 'ethers' const REVERT = env.bool("REVERT", true); @@ -54,10 +53,9 @@ scenario("Optimism :: Launch integration test", ctxFactory) .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); const { l1Provider, l2Provider, l1LidoTokensBridge } = await optimism - .testing(networkName) + .testing() .getIntegrationTestSetup(); const hasDeployedContracts = testing.env.USE_DEPLOYED_CONTRACTS(false); diff --git a/test/integration/bridging-rebasable.integration.test.ts b/test/integration/bridging-rebasable.integration.test.ts index 68397e6c..ca2ca334 100644 --- a/test/integration/bridging-rebasable.integration.test.ts +++ b/test/integration/bridging-rebasable.integration.test.ts @@ -1,6 +1,5 @@ import { assert } from "chai"; import { BigNumber, ethers } from 'ethers' -import env from "../../utils/env"; import { wei } from "../../utils/wei"; import optimism from "../../utils/optimism"; import testing, { scenario, ScenarioTest } from "../../utils/testing"; @@ -744,7 +743,6 @@ function ctxFactory( ) { return async () => { const hasDeployedContracts = testing.env.USE_DEPLOYED_CONTRACTS(false); - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); const { totalPooledEther, @@ -754,12 +752,12 @@ function ctxFactory( l1ERC20ExtendedTokensBridgeAdmin, l2ERC20ExtendedTokensBridgeAdmin, ...contracts - } = await optimism.testing(networkName).getIntegrationTestSetup(); + } = await optimism.testing().getIntegrationTestSetup(); const l1Snapshot = await l1Provider.send("evm_snapshot", []); const l2Snapshot = await l2Provider.send("evm_snapshot", []); - await optimism.testing(networkName).stubL1CrossChainMessengerContract(); + await optimism.testing().stubL1CrossChainMessengerContract(); const accountA = testing.accounts.accountA(l1Provider, l2Provider); const accountB = testing.accounts.accountB(l1Provider, l2Provider); diff --git a/test/integration/deposit-gas-estimation.test.ts b/test/integration/deposit-gas-estimation.test.ts index 91258b44..36362e5a 100644 --- a/test/integration/deposit-gas-estimation.test.ts +++ b/test/integration/deposit-gas-estimation.test.ts @@ -1,6 +1,4 @@ import { assert } from "chai"; - -import env from "../../utils/env"; import { wei } from "../../utils/wei"; import optimism from "../../utils/optimism"; import testing, { scenario } from "../../utils/testing"; @@ -128,22 +126,16 @@ scenario("Optimism :: Bridging integration test", ctxFactory) const gasDifference = receipt1.gasUsed.sub(receipt0.gasUsed); console.log("gasUsed difference=", gasDifference); }) - - - .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); - console.log("networkName=", networkName); - const { l1Provider, l2Provider, l1ERC20ExtendedTokensBridgeAdmin, l2ERC20ExtendedTokensBridgeAdmin, ...contracts - } = await optimism.testing(networkName).getIntegrationTestSetup(); + } = await optimism.testing().getIntegrationTestSetup(); const l1Snapshot = await l1Provider.send("evm_snapshot", []); const l2Snapshot = await l2Provider.send("evm_snapshot", []); diff --git a/test/integration/pushingTokenRate.integration.test.ts b/test/integration/notifier-pushing-token-rate.integration.test.ts similarity index 94% rename from test/integration/pushingTokenRate.integration.test.ts rename to test/integration/notifier-pushing-token-rate.integration.test.ts index 66b61aa6..97e3eaa8 100644 --- a/test/integration/pushingTokenRate.integration.test.ts +++ b/test/integration/notifier-pushing-token-rate.integration.test.ts @@ -121,8 +121,6 @@ scenario("Optimism :: Token Rate Oracle integration test", ctxFactory) .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); - const { totalPooledEther, totalShares, @@ -131,17 +129,17 @@ async function ctxFactory() { l1ERC20ExtendedTokensBridgeAdmin, l2ERC20ExtendedTokensBridgeAdmin, ...contracts - } = await optimism.testing(networkName).getIntegrationTestSetup(); + } = await optimism.testing().getIntegrationTestSetup(); const lidoAsEOA = await testing.impersonate(env.address("LIDO"), l1Provider); const tokenRateDecimals = BigNumber.from(27); const tokenRate = getExchangeRate(tokenRateDecimals, totalPooledEther, totalShares); - const optContracts = optimism.contracts(networkName, { forking: true }); + const optContracts = optimism.contracts({ forking: true }); const l2CrossDomainMessenger = optContracts.L2CrossDomainMessenger; - await optimism.testing(networkName).stubL1CrossChainMessengerContract(); + await optimism.testing().stubL1CrossChainMessengerContract(); const l1CrossDomainMessengerAliased = await testing.impersonate( testing.accounts.applyL1ToL2Alias(optContracts.L1CrossDomainMessengerStub.address), diff --git a/test/integration/op-pusher-pushing-token-rate.integration.test.ts b/test/integration/op-pusher-pushing-token-rate.integration.test.ts new file mode 100644 index 00000000..b4020138 --- /dev/null +++ b/test/integration/op-pusher-pushing-token-rate.integration.test.ts @@ -0,0 +1,175 @@ +import { assert } from "chai"; +import { BigNumber } from "ethers"; +import { wei } from "../../utils/wei"; +import optimism from "../../utils/optimism"; +import testing, { scenario } from "../../utils/testing"; +import { getExchangeRate, refSlotTimestamp } from "../../utils/testing/helpers"; + +scenario("Optimism :: Token Rate Oracle integration test", ctxFactory) + + .step("Push Token Rate", async (ctx) => { + const { + tokenRateOracle, + opTokenRatePusher, + l1CrossDomainMessenger, + accountingOracle + } = ctx; + + const { + tokenRate, + } = ctx.constants; + + const account = ctx.accounts.accountA; + + const tx = await opTokenRatePusher + .connect(account.l1Signer) + .pushTokenRate(); + + const messageNonce = await l1CrossDomainMessenger.messageNonce(); + const updateRateTime = await refSlotTimestamp(accountingOracle); + const l2Calldata = tokenRateOracle.interface.encodeFunctionData( + "updateRate", + [ + tokenRate, + updateRateTime + ] + ); + + await assert.emits(l1CrossDomainMessenger, tx, "SentMessage", [ + tokenRateOracle.address, + opTokenRatePusher.address, + l2Calldata, + messageNonce, + 300_000, + ]); + }) + + .step("Finalize pushing rate", async (ctx) => { + const { + opTokenRatePusher, + tokenRateOracle, + l1CrossDomainMessenger, + accountingOracle + } = ctx; + + const [ + , + tokenRateAnswerBefore, + startedAt_updatedRateBefore, + , + ] = await tokenRateOracle.latestRoundData(); + + console.log("tokenRateAnswerBefore=", tokenRateAnswerBefore); + console.log("startedAt_updatedRateBefore=",startedAt_updatedRateBefore); + + const { + tokenRate + } = ctx.constants; + + const account = ctx.accounts.accountA; + await l1CrossDomainMessenger + .connect(account.l1Signer) + .setXDomainMessageSender(opTokenRatePusher.address); + + const minTimeBetweenTokenRateUpdates = await tokenRateOracle.MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES(); + const updateRateTime = (await refSlotTimestamp(accountingOracle)) + .add(minTimeBetweenTokenRateUpdates) + .add(1000); + + const messageNonce = await l1CrossDomainMessenger.messageNonce(); + + const tx = await ctx.l2CrossDomainMessenger + .connect(ctx.accounts.l1CrossDomainMessengerAliased) + .relayMessage( + messageNonce, + opTokenRatePusher.address, + tokenRateOracle.address, + 0, + 300_000, + tokenRateOracle.interface.encodeFunctionData("updateRate", [ + tokenRate, + updateRateTime + ]), + { gasLimit: 5_000_000 } + ); + + console.log("new tokenRate=",tokenRate); + console.log("new updateRateTime=",updateRateTime); + + if ((updateRateTime.sub(startedAt_updatedRateBefore)).gt(minTimeBetweenTokenRateUpdates)) { + await assert.emits(tokenRateOracle, tx, "RateUpdated", [ + tokenRate, + updateRateTime + ]); + } + + const answer = await tokenRateOracle.latestAnswer(); + assert.equalBN(answer, tokenRate); + + const [ + , + tokenRateAnswer, + startedAt_, + , + ] = await tokenRateOracle.latestRoundData(); + + assert.equalBN(tokenRateAnswer, tokenRate); + assert.equalBN(startedAt_, updateRateTime); + }) + + .run(); + +async function ctxFactory() { + const { + totalPooledEther, + totalShares, + l1Provider, + l2Provider, + l1ERC20ExtendedTokensBridgeAdmin, + l2ERC20ExtendedTokensBridgeAdmin, + ...contracts + } = await optimism.testing().getIntegrationTestSetup(); + + const tokenRateDecimals = BigNumber.from(27); + const tokenRate = getExchangeRate(tokenRateDecimals, totalPooledEther, totalShares); + + const optContracts = optimism.contracts({ forking: true }); + const l2CrossDomainMessenger = optContracts.L2CrossDomainMessenger; + + await optimism.testing().stubL1CrossChainMessengerContract(); + + const l1CrossDomainMessengerAliased = await testing.impersonate( + testing.accounts.applyL1ToL2Alias(optContracts.L1CrossDomainMessengerStub.address), + l2Provider + ); + await testing.setBalance( + await l1CrossDomainMessengerAliased.getAddress(), + wei.toBigNumber(wei`1 ether`), + l2Provider + ); + + const tokenRateOracle = contracts.tokenRateOracle; + const opTokenRatePusher = contracts.opStackTokenRatePusher; + const l1Token = contracts.l1Token; + const accountingOracle = contracts.accountingOracle; + + const accountA = testing.accounts.accountA(l1Provider, l2Provider); + const l1CrossDomainMessenger = optContracts.L1CrossDomainMessengerStub; + + return { + tokenRateOracle, + opTokenRatePusher, + l1CrossDomainMessenger, + l2CrossDomainMessenger, + l1Token, + accountingOracle, + l1Provider, + accounts: { + accountA, + l1CrossDomainMessengerAliased + }, + constants: { + tokenRate + } + }; +} diff --git a/test/integration/optimism.integration.test.ts b/test/integration/optimism.integration.test.ts index 509b7226..679aeff3 100644 --- a/test/integration/optimism.integration.test.ts +++ b/test/integration/optimism.integration.test.ts @@ -1,13 +1,12 @@ import { assert } from "chai"; import { BigNumber } from 'ethers' import { wei } from "../../utils/wei"; -import env from "../../utils/env"; import optimism from "../../utils/optimism"; import testing, { scenario } from "../../utils/testing"; import { BridgingManagerRole } from "../../utils/bridging-management"; import { getExchangeRate } from "../../utils/testing/helpers"; import { getBridgeExecutorParams } from "../../utils/bridge-executor"; -import deploymentAll from "../../utils/optimism/deployment"; +import deployAll from "../../utils/optimism/deployAll"; import network from "../../utils/network"; import { StETHStub__factory, @@ -200,9 +199,7 @@ scenario("Optimism :: Bridge Executor integration test", ctxFactory) .run(); async function ctxFactory() { - const networkName = env.network("TESTING_OPT_NETWORK", "mainnet"); const [l1Provider, l2Provider] = network - .multichain(["eth", "opt"], networkName) .getProviders({ forking: true }); const l1Deployer = testing.accounts.deployer(l1Provider); @@ -255,7 +252,7 @@ async function ctxFactory() { decimals: 18 }; - await optimism.testing(networkName).stubL1CrossChainMessengerContract(); + await optimism.testing().stubL1CrossChainMessengerContract(); const l1TokenRebasable = await new StETHStub__factory(l1Deployer).deploy( l1TokenRebasableName, @@ -276,7 +273,7 @@ async function ctxFactory() { lastProcessingRefSlot ); - const optAddresses = optimism.addresses(networkName); + const optAddresses = optimism.addresses(); const testingOnDeployedContracts = testing.env.USE_DEPLOYED_CONTRACTS(false); const govBridgeExecutor = testingOnDeployedContracts @@ -294,15 +291,15 @@ async function ctxFactory() { const l1EthGovExecutorAddress = await govBridgeExecutor.getEthereumGovernanceExecutor(); - const [, optDeployScript] = await deploymentAll( - networkName - ).deployAllScript( + const [, optDeployScript] = await deployAll(true) + .deployAllScript( { l1TokenNonRebasable: l1TokenNonRebasable.address, l1TokenRebasable: l1TokenRebasable.address, accountingOracle: accountingOracle.address, l2GasLimitForPushingTokenRate: l2GasLimitForPushingTokenRate, lido: lido.address, + l1CrossDomainMessenger: optAddresses.L1CrossDomainMessenger, deployer: l1Deployer, admins: { @@ -313,6 +310,7 @@ async function ctxFactory() { }, { tokenRateOracle: { + admin: l2Deployer.address, tokenRateOutdatedDelay: tokenRateOutdatedDelay, maxAllowedL2ToL1ClockLag: maxAllowedL2ToL1ClockLag, maxAllowedTokenRateDeviationPerDayBp: maxAllowedTokenRateDeviationPerDay, @@ -321,6 +319,7 @@ async function ctxFactory() { tokenRate: exchangeRate, l1Timestamp: l1Timestamp }, + l2CrossDomainMessenger: optAddresses.L2CrossDomainMessenger, l2TokenNonRebasable: { name: l2TokenNonRebasable.name, symbol: l2TokenNonRebasable.symbol, @@ -358,7 +357,7 @@ async function ctxFactory() { l2Deployer ); - const optContracts = optimism.contracts(networkName, { forking: true }); + const optContracts = optimism.contracts({ forking: true }); const l1CrossDomainMessengerAliased = await testing.impersonate( testing.accounts.applyL1ToL2Alias( diff --git a/test/managing-e2e/managing-deposits.e2e.test.ts b/test/managing-e2e/managing-deposits.e2e.test.ts index 36712d50..4893e4a6 100644 --- a/test/managing-e2e/managing-deposits.e2e.test.ts +++ b/test/managing-e2e/managing-deposits.e2e.test.ts @@ -63,7 +63,7 @@ const scenarioTest = scenario( [false, false], ]); - const optAddresses = optimism.addresses("sepolia"); + const optAddresses = optimism.addresses(); const { calldata, callvalue } = await ctx.messaging.prepareL2Message({ sender: ctx.lidoAragonDAO.agent.address, @@ -138,22 +138,20 @@ scenarioTest.run(); scenarioTest.run(); async function ctxFactory() { - const ethOptNetwork = network.multichain(["eth", "opt"], "sepolia"); - - const [l1Provider] = ethOptNetwork.getProviders({ forking: false }); - const [l1Tester, l2Tester] = ethOptNetwork.getSigners( + const [l1Provider] = network.getProviders({ forking: false }); + const [l1Tester, l2Tester] = network.getSigners( env.string("TESTING_PRIVATE_KEY"), { forking: false } ); - const [l1LDOHolder] = ethOptNetwork.getSigners( + const [l1LDOHolder] = network.getSigners( env.string("TESTING_OPT_LDO_HOLDER_PRIVATE_KEY"), { forking: false } ); return { lidoAragonDAO: lido("sepolia", l1Provider), - messaging: optimism.messaging("sepolia", { forking: false }), + messaging: optimism.messaging({ forking: false }), gasAmount: wei`0.1 ether`, l1Tester, l2Tester, diff --git a/test/managing-e2e/managing-executor.e2e.test.ts b/test/managing-e2e/managing-executor.e2e.test.ts index f48112e9..82326ff9 100644 --- a/test/managing-e2e/managing-executor.e2e.test.ts +++ b/test/managing-e2e/managing-executor.e2e.test.ts @@ -47,7 +47,7 @@ scenario("Optimism :: AAVE governance crosschain bridge management", ctxFactory) [false], ]); - const optAddresses = optimism.addresses("sepolia"); + const optAddresses = optimism.addresses(); const { calldata, callvalue } = await ctx.messaging.prepareL2Message({ sender: ctx.lidoAragonDAO.agent.address, @@ -115,22 +115,20 @@ scenario("Optimism :: AAVE governance crosschain bridge management", ctxFactory) .run(); async function ctxFactory() { - const ethOptNetwork = network.multichain(["eth", "opt"], "sepolia"); - - const [l1Provider] = ethOptNetwork.getProviders({ forking: false }); - const [, l2Tester] = ethOptNetwork.getSigners( + const [l1Provider] = network.getProviders({ forking: false }); + const [, l2Tester] = network.getSigners( env.string("TESTING_PRIVATE_KEY"), { forking: false } ); - const [l1LDOHolder] = ethOptNetwork.getSigners( + const [l1LDOHolder] = network.getSigners( env.string("TESTING_OPT_LDO_HOLDER_PRIVATE_KEY"), { forking: false } ); return { lidoAragonDAO: lido("sepolia", l1Provider), - messaging: optimism.messaging("sepolia", { forking: false }), + messaging: optimism.messaging({ forking: false }), gasAmount: wei`0.1 ether`, l2Tester, l1LDOHolder, diff --git a/test/managing-e2e/managing-proxy.e2e.test.ts b/test/managing-e2e/managing-proxy.e2e.test.ts index 8c5ddcc2..03165a74 100644 --- a/test/managing-e2e/managing-proxy.e2e.test.ts +++ b/test/managing-e2e/managing-proxy.e2e.test.ts @@ -47,7 +47,7 @@ scenario( [false], ]); - const optAddresses = optimism.addresses("sepolia"); + const optAddresses = optimism.addresses(); const { calldata, callvalue } = await ctx.messaging.prepareL2Message({ sender: ctx.lidoAragonDAO.agent.address, @@ -118,7 +118,7 @@ scenario( [false], ]); - const optAddresses = optimism.addresses("sepolia"); + const optAddresses = optimism.addresses(); const { calldata, callvalue } = await ctx.messaging.prepareL2Message({ sender: ctx.lidoAragonDAO.agent.address, @@ -180,22 +180,20 @@ scenario( .run(); async function ctxFactory() { - const ethOptNetwork = network.multichain(["eth", "opt"], "sepolia"); - - const [l1Provider] = ethOptNetwork.getProviders({ forking: false }); - const [l1Tester, l2Tester] = ethOptNetwork.getSigners( + const [l1Provider] = network.getProviders({ forking: false }); + const [l1Tester, l2Tester] = network.getSigners( env.string("TESTING_PRIVATE_KEY"), { forking: false } ); - const [l1LDOHolder] = ethOptNetwork.getSigners( + const [l1LDOHolder] = network.getSigners( env.string("TESTING_OPT_LDO_HOLDER_PRIVATE_KEY"), { forking: false } ); return { lidoAragonDAO: lido("sepolia", l1Provider), - messaging: optimism.messaging("sepolia", { forking: false }), + messaging: optimism.messaging({ forking: false }), gasAmount: wei`0.1 ether`, l1Tester, l2Tester, diff --git a/utils/deployment.ts b/utils/deployment.ts index 187d3301..ab8f359d 100644 --- a/utils/deployment.ts +++ b/utils/deployment.ts @@ -5,30 +5,41 @@ import env from "./env"; import { DeployScript } from "./deployment/DeployScript"; import { BridgingManagerSetupConfig } from "./bridging-management"; -interface EthereumDeploymentConfig extends BridgingManagerSetupConfig { - bridgeProxyAdmin: string; - l1TokenNonRebasable: string; - l1RebasableToken: string; - accountingOracle: string; - l2GasLimitForPushingTokenRate: BigNumber; +interface L1StETHDeploymentConfig extends L1ScratchDeploymentConfig { l1TokenBridge: string; +} + +interface L1ScratchDeploymentConfig extends L1DeploymentConfig { lido: string; tokenRateNotifierOwner: string; } -interface OptimismDeploymentConfig extends BridgingManagerSetupConfig { - bridgeProxyAdmin: string; +interface L1DeploymentConfig extends BridgingManagerSetupConfig { + l1CrossDomainMessenger: string; + proxyAdmin: string; + accountingOracle: string; + l1TokenNonRebasable: string; + l1RebasableToken: string; + l2GasLimitForPushingTokenRate: BigNumber; +} + +interface L2StETHDeploymentConfig extends L2ScratchDeploymentConfig { + l2TokenBridge: string; + l2TokenNonRebasable: string; +} - govBridgeExecutor: string; +interface L2ScratchDeploymentConfig extends L2DeploymentConfig { +} + +interface L2DeploymentConfig extends BridgingManagerSetupConfig { + l2CrossDomainMessenger: string; /// Oracle - tokenRateOracleProxyAdmin: string; tokenRateOracleAdmin: string; tokenRateUpdateEnabled: boolean; tokenRateUpdateDisablers?: string[], tokenRateUpdateEnablers?: string[], - tokenRateOutdatedDelay: BigNumber; maxAllowedL2ToL1ClockLag: BigNumber; maxAllowedTokenRateDeviationPerDayBp: BigNumber; @@ -38,87 +49,147 @@ interface OptimismDeploymentConfig extends BridgingManagerSetupConfig { initialTokenRateL1Timestamp: BigNumber; /// L2 wstETH address to upgrade - l2TokenNonRebasableAddress: string; + l2TokenNonRebasableName?: string; + l2TokenNonRebasableSymbol?: string; l2TokenNonRebasableDomainVersion: string; /// L2 stETH + l2TokenRebasableName?: string; + l2TokenRebasableSymbol?: string; l2TokenRebasableDomainVersion: string; - l2TokenRebasableProxyAdmin: string; /// bridge - l2TokenBridge: string; + proxyAdmin: string; +} + +interface MultiChainStETHDeploymentConfig { + l1: L1StETHDeploymentConfig; + l2: L2StETHDeploymentConfig; +} + +interface MultiChainScratchDeploymentConfig { + l1: L1ScratchDeploymentConfig; + l2: L2ScratchDeploymentConfig; } interface MultiChainDeploymentConfig { - ethereum: EthereumDeploymentConfig; - optimism: OptimismDeploymentConfig; + l1: L1DeploymentConfig; + l2: L2DeploymentConfig; +} + +export function loadL1StETHDeploymentConfig(): L1StETHDeploymentConfig { + return { + ...loadL1ScratchDeploymentConfig(), + l1TokenBridge: env.address("L1_TOKEN_BRIDGE"), + } +} + +export function loadL2StETHDeploymentConfig(): L2StETHDeploymentConfig { + return { + ...loadL2ScratchDeploymentConfig(), + l2TokenBridge: env.address("L2_TOKEN_BRIDGE"), + l2TokenNonRebasable: env.address("L2_TOKEN_NON_REBASABLE"), + } +} + +export function loadL1ScratchDeploymentConfig(): L1ScratchDeploymentConfig { + return { + ...loadL1DeploymentConfig(), + lido: env.address("LIDO"), + tokenRateNotifierOwner: env.address("TOKEN_RATE_NOTIFIER_OWNER"), + }; +} + +export function loadL2ScratchDeploymentConfig(): L2ScratchDeploymentConfig { + return { + ...loadL2ScratchDeploymentConfig() + }; +} + +export function loadL1DeploymentConfig(): L1DeploymentConfig { + return { + l1CrossDomainMessenger: env.address("L1_CROSSDOMAIN_MESSENGER"), + proxyAdmin: env.address("L1_PROXY_ADMIN"), + + l1TokenNonRebasable: env.address("L1_NON_REBASABLE_TOKEN"), + l1RebasableToken: env.address("L1_REBASABLE_TOKEN"), + accountingOracle: env.address("ACCOUNTING_ORACLE"), + l2GasLimitForPushingTokenRate: BigNumber.from(env.string("L2_GAS_LIMIT_FOR_PUSHING_TOKEN_RATE")), + + // Bridge + bridgeAdmin: env.address("L1_BRIDGE_ADMIN"), + depositsEnabled: env.bool("L1_DEPOSITS_ENABLED", false), + withdrawalsEnabled: env.bool("L1_WITHDRAWALS_ENABLED", false), + depositsEnablers: env.addresses("L1_DEPOSITS_ENABLERS", []), + depositsDisablers: env.addresses("L1_DEPOSITS_DISABLERS", []), + withdrawalsEnablers: env.addresses("L1_WITHDRAWALS_ENABLERS", []), + withdrawalsDisablers: env.addresses("L1_WITHDRAWALS_DISABLERS", []), + }; +} + +export function loadL2DeploymentConfig(): L2DeploymentConfig { + return { + l2CrossDomainMessenger: env.address("L2_CROSSDOMAIN_MESSENGER"), + proxyAdmin: env.address("L2_PROXY_ADMIN"), + + /// TokenRateOracle + tokenRateOracleAdmin: env.address("TOKEN_RATE_ORACLE_ADMIN"), + tokenRateUpdateEnabled: env.bool("TOKEN_RATE_UPDATE_ENABLED", true), + tokenRateUpdateDisablers: env.addresses("TOKEN_RATE_UPDATE_DISABLERS", []), + tokenRateUpdateEnablers: env.addresses("TOKEN_RATE_UPDATE_ENABLERS", []), + + tokenRateOutdatedDelay: BigNumber.from(env.string("TOKEN_RATE_OUTDATED_DELAY")), + maxAllowedL2ToL1ClockLag: BigNumber.from(env.string("MAX_ALLOWED_L2_TO_L1_CLOCK_LAG")), + maxAllowedTokenRateDeviationPerDayBp: BigNumber.from(env.string("MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP")), + oldestRateAllowedInPauseTimeSpan: BigNumber.from(env.string("OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN")), + minTimeBetweenTokenRateUpdates: BigNumber.from(env.string("MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES")), + initialTokenRateValue: BigNumber.from(env.string("INITIAL_TOKEN_RATE_VALUE")), + initialTokenRateL1Timestamp: BigNumber.from(env.string("INITIAL_TOKEN_RATE_L1_TIMESTAMP")), + + // wstETH + l2TokenNonRebasableName: env.string("L2_TOKEN_NON_REBASABLE_NAME"), + l2TokenNonRebasableSymbol: env.string("L2_TOKEN_NON_REBASABLE_SYMBOL"), + l2TokenNonRebasableDomainVersion: env.string("L2_TOKEN_NON_REBASABLE_SIGNING_DOMAIN_VERSION"), + + // stETH + l2TokenRebasableName: env.string("L2_TOKEN_REBASABLE_NAME"), + l2TokenRebasableSymbol: env.string("L2_TOKEN_REBASABLE_SYMBOL"), + l2TokenRebasableDomainVersion: env.string("L2_TOKEN_REBASABLE_SIGNING_DOMAIN_VERSION"), + + // Bridge + bridgeAdmin: env.address("L2_BRIDGE_ADMIN"), + depositsEnabled: env.bool("L2_DEPOSITS_ENABLED", false), + withdrawalsEnabled: env.bool("L2_WITHDRAWALS_ENABLED", false), + depositsEnablers: env.addresses("L2_DEPOSITS_ENABLERS", []), + depositsDisablers: env.addresses("L2_DEPOSITS_DISABLERS", []), + withdrawalsEnablers: env.addresses("L2_WITHDRAWALS_ENABLERS", []), + withdrawalsDisablers: env.addresses("L2_WITHDRAWALS_DISABLERS", []), + }; +} + +export function loadMultiChainStETHDeploymentConfig(): MultiChainStETHDeploymentConfig { + return { + l1: loadL1StETHDeploymentConfig(), + l2: loadL2StETHDeploymentConfig() + }; } export function loadMultiChainDeploymentConfig(): MultiChainDeploymentConfig { return { - ethereum: { - l1TokenNonRebasable: env.address("L1_NON_REBASABLE_TOKEN"), - l1RebasableToken: env.address("L1_REBASABLE_TOKEN"), - accountingOracle: env.address("ACCOUNTING_ORACLE"), - l2GasLimitForPushingTokenRate: BigNumber.from(env.string("L2_GAS_LIMIT_FOR_PUSHING_TOKEN_RATE")), - l1TokenBridge: env.address("L1_TOKEN_BRIDGE"), - lido: env.address("LIDO"), - tokenRateNotifierOwner: env.address("TOKEN_RATE_NOTIFIER_OWNER"), - - // Bridge - bridgeProxyAdmin: env.address("L1_PROXY_ADMIN"), - bridgeAdmin: env.address("L1_BRIDGE_ADMIN"), - depositsEnabled: env.bool("L1_DEPOSITS_ENABLED", false), - withdrawalsEnabled: env.bool("L1_WITHDRAWALS_ENABLED", false), - depositsEnablers: env.addresses("L1_DEPOSITS_ENABLERS", []), - depositsDisablers: env.addresses("L1_DEPOSITS_DISABLERS", []), - withdrawalsEnablers: env.addresses("L1_WITHDRAWALS_ENABLERS", []), - withdrawalsDisablers: env.addresses("L1_WITHDRAWALS_DISABLERS", []), - }, - optimism: { - govBridgeExecutor: env.address("GOV_BRIDGE_EXECUTOR"), - - /// TokenRateOracle - tokenRateOracleProxyAdmin: env.address("TOKEN_RATE_ORACLE_PROXY_ADMIN"), - tokenRateOracleAdmin: env.address("TOKEN_RATE_ORACLE_ADMIN"), - tokenRateUpdateEnabled: env.bool("TOKEN_RATE_UPDATE_ENABLED", true), - tokenRateUpdateDisablers: env.addresses("TOKEN_RATE_UPDATE_DISABLERS", []), - tokenRateUpdateEnablers: env.addresses("TOKEN_RATE_UPDATE_ENABLERS", []), - - tokenRateOutdatedDelay: BigNumber.from(env.string("TOKEN_RATE_OUTDATED_DELAY")), - maxAllowedL2ToL1ClockLag: BigNumber.from(env.string("MAX_ALLOWED_L2_TO_L1_CLOCK_LAG")), - maxAllowedTokenRateDeviationPerDayBp: BigNumber.from(env.string("MAX_ALLOWED_TOKEN_RATE_DEVIATION_PER_DAY_BP")), - oldestRateAllowedInPauseTimeSpan: BigNumber.from(env.string("OLDEST_RATE_ALLOWED_IN_PAUSE_TIME_SPAN")), - minTimeBetweenTokenRateUpdates: BigNumber.from(env.string("MIN_TIME_BETWEEN_TOKEN_RATE_UPDATES")), - initialTokenRateValue: BigNumber.from(env.string("INITIAL_TOKEN_RATE_VALUE")), - initialTokenRateL1Timestamp: BigNumber.from(env.string("INITIAL_TOKEN_RATE_L1_TIMESTAMP")), - - // wstETH - l2TokenNonRebasableAddress: env.address("L2_TOKEN_NON_REBASABLE"), - l2TokenNonRebasableDomainVersion: env.string("L2_TOKEN_NON_REBASABLE_SIGNING_DOMAIN_VERSION"), - - // stETH - l2TokenRebasableDomainVersion: env.string("L2_TOKEN_REBASABLE_SIGNING_DOMAIN_VERSION"), - l2TokenRebasableProxyAdmin: env.string("L2_TOKEN_REBASABLE_PROXY_ADMIN"), - - // Bridge - l2TokenBridge: env.address("L2_TOKEN_BRIDGE"), - - bridgeProxyAdmin: env.address("L2_PROXY_ADMIN"), - bridgeAdmin: env.address("L2_BRIDGE_ADMIN"), - depositsEnabled: env.bool("L2_DEPOSITS_ENABLED", false), - withdrawalsEnabled: env.bool("L2_WITHDRAWALS_ENABLED", false), - depositsEnablers: env.addresses("L2_DEPOSITS_ENABLERS", []), - depositsDisablers: env.addresses("L2_DEPOSITS_DISABLERS", []), - withdrawalsEnablers: env.addresses("L2_WITHDRAWALS_ENABLERS", []), - withdrawalsDisablers: env.addresses("L2_WITHDRAWALS_DISABLERS", []), - }, + l1: loadL1DeploymentConfig(), + l2: loadL2DeploymentConfig() + }; +} + +export function loadMultiChainScratchDeploymentConfig(): MultiChainScratchDeploymentConfig { + return { + l1: loadL1ScratchDeploymentConfig(), + l2: loadL2ScratchDeploymentConfig() }; } export async function printDeploymentConfig() { const pad = " ".repeat(4); - console.log(`${pad}· Network: ${env.string("NETWORK")}`); console.log(`${pad}· Forking: ${env.bool("FORKING")}`); } @@ -131,7 +202,7 @@ export async function printMultiChainDeploymentConfig( l2DeployScript: DeployScript, scratchDeploy: boolean ) { - const { ethereum, optimism } = deploymentParams; + const { l1, l2 } = deploymentParams; console.log(chalk.bold(`${title}\n`)); console.log(chalk.bold(" · Deployment Params:")); @@ -139,22 +210,21 @@ export async function printMultiChainDeploymentConfig( console.log(); console.log(chalk.bold(" · L1 Deployment Params:")); - await printEthereumDeploymentConfig(l1Deployer, ethereum, scratchDeploy); + await printL1DeploymentConfig(l1Deployer, l1, scratchDeploy); console.log(); console.log(chalk.bold(" · L1 Deployment Actions:")); l1DeployScript.print({ padding: 6 }); console.log(chalk.bold(" · L2 Deployment Params:")); - await printOptimismDeploymentConfig(l2Deployer, optimism, scratchDeploy); + await printL2DeploymentConfig(l2Deployer, l2, scratchDeploy); console.log(); console.log(chalk.bold(" · L2 Deployment Actions:")); l2DeployScript.print({ padding: 6 }); } - -async function printEthereumDeploymentConfig( +async function printL1DeploymentConfig( deployer: Wallet, - params: EthereumDeploymentConfig, + params: L1DeploymentConfig, scratchDeploy: boolean ) { const pad = " ".repeat(4); @@ -162,17 +232,14 @@ async function printEthereumDeploymentConfig( console.log(`${pad}· Chain ID: ${chainId}`); console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); + console.log(`${pad}·· Proxy Admin: ${chalk.underline(params.proxyAdmin)}`); console.log(`${pad}· l1TokenNonRebasable: ${chalk.underline(params.l1TokenNonRebasable)}`); console.log(`${pad}· l1RebasableToken: ${chalk.underline(params.l1RebasableToken)}`); console.log(`${pad}· accountingOracle: ${chalk.underline(params.accountingOracle)}`); console.log(`${pad}· l2GasLimitForPushingTokenRate: ${chalk.underline(params.l2GasLimitForPushingTokenRate)}`); - console.log(`${pad}· l1TokenBridge: ${chalk.underline(params.l1TokenBridge)}`); - console.log(`${pad}· lido: ${chalk.underline(params.lido)}`); - console.log(`${pad}· tokenRateNotifierOwner: ${chalk.underline(params.tokenRateNotifierOwner)}`); if(scratchDeploy) { console.log(`${pad}· Ethereum Bridge`); - console.log(`${pad}·· Proxy Admin: ${chalk.underline(params.bridgeProxyAdmin)}`); console.log(`${pad}·· Bridge Admin: ${chalk.underline(params.bridgeAdmin)}`); console.log(`${pad}·· Deposits Enabled: ${params.depositsEnabled}`); console.log( @@ -197,17 +264,16 @@ async function printEthereumDeploymentConfig( } } -async function printOptimismDeploymentConfig( +async function printL2DeploymentConfig( deployer: Wallet, - params: OptimismDeploymentConfig, + params: L2DeploymentConfig, scratchDeploy: boolean ) { const pad = " ".repeat(4); const chainId = await deployer.getChainId(); console.log(`${pad}· Chain ID: ${chainId}`); console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); - console.log(`${pad}· govBridgeExecutor: ${chalk.underline(params.govBridgeExecutor)}`); - console.log(`${pad}· tokenRateOracleProxyAdmin: ${chalk.underline(params.tokenRateOracleProxyAdmin)}`); + console.log(`${pad}·· Proxy Admin: ${chalk.underline(params.proxyAdmin)}`); console.log(`${pad}· tokenRateOracleAdmin: ${chalk.underline(params.tokenRateOracleAdmin)}`); console.log(`${pad}· tokenRateUpdateEnabled: ${chalk.underline(params.tokenRateUpdateEnabled)}`); console.log(`${pad}· tokenRateUpdateDisablers: ${chalk.underline(params.tokenRateUpdateDisablers)}`); @@ -219,15 +285,11 @@ async function printOptimismDeploymentConfig( console.log(`${pad}· minTimeBetweenTokenRateUpdates: ${chalk.underline(params.minTimeBetweenTokenRateUpdates)}`); console.log(`${pad}· initialTokenRateValue: ${chalk.underline(params.initialTokenRateValue)}`); console.log(`${pad}· initialTokenRateL1Timestamp: ${chalk.underline(params.initialTokenRateL1Timestamp)}`); - console.log(`${pad}· l2TokenNonRebasableAddress: ${chalk.underline(params.l2TokenNonRebasableAddress)}`); console.log(`${pad}· l2TokenNonRebasableDomainVersion: ${chalk.underline(params.l2TokenNonRebasableDomainVersion)}`); - console.log(`${pad}· l2TokenRebasableProxyAdmin: ${chalk.underline(params.l2TokenRebasableProxyAdmin)}`); console.log(`${pad}· l2TokenRebasableDomainVersion: ${chalk.underline(params.l2TokenRebasableDomainVersion)}`); - console.log(`${pad}· l2TokenBridge: ${chalk.underline(params.l2TokenBridge)}`); if (scratchDeploy) { console.log(`${pad}· Optimism Bridge`); - console.log(`${pad}·· Proxy Admin: ${chalk.underline(params.bridgeProxyAdmin)}`); console.log(`${pad}·· Admin: ${chalk.underline(params.bridgeAdmin)}`); console.log(`${pad}·· Deposits Enabled: ${params.depositsEnabled}`); console.log( @@ -252,7 +314,132 @@ async function printOptimismDeploymentConfig( } } +export async function printMultiChainStETHDeploymentConfig( + title: string, + l1Deployer: Wallet, + l2Deployer: Wallet, + deploymentParams: MultiChainStETHDeploymentConfig, + l1DeployScript: DeployScript, + l2DeployScript: DeployScript, +) { + const { l1, l2 } = deploymentParams; + console.log(chalk.bold(`${title}\n`)); + + console.log(chalk.bold(" · Deployment Params:")); + await printDeploymentConfig(); + console.log(); + + console.log(chalk.bold(" · L1 StETH Deployment Params:")); + await printL1StETHConfig(l1Deployer, l1); + console.log(); + console.log(chalk.bold(" · L1 Deployment Actions:")); + l1DeployScript.print({ padding: 6 }); + + console.log(chalk.bold(" · L2 StETH Deployment Params:")); + await printL2StETHConfig(l2Deployer, l2); + console.log(); + console.log(chalk.bold(" · L2 Deployment Actions:")); + l2DeployScript.print({ padding: 6 }); +} + +async function printL1StETHConfig( + deployer: Wallet, + params: L1StETHDeploymentConfig +) { + const pad = " ".repeat(4); + const chainId = await deployer.getChainId(); + console.log(`${pad}· Chain ID: ${chainId}`); + console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); + + // Print base config + await printL1DeploymentConfig(deployer, params, false); + + // Print StETH specific fields + console.log(`${pad}· L1 Token Bridge: ${chalk.underline(params.l1TokenBridge)}`); + console.log(`${pad}· Lido: ${chalk.underline(params.lido)}`); + console.log(`${pad}· Token Rate Notifier Owner: ${chalk.underline(params.tokenRateNotifierOwner)}`); +} + +async function printL2StETHConfig( + deployer: Wallet, + params: L2StETHDeploymentConfig +) { + const pad = " ".repeat(4); + const chainId = await deployer.getChainId(); + console.log(`${pad}· Chain ID: ${chainId}`); + console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); + + // Print base config + await printL2DeploymentConfig(deployer, params, false); + + // Print StETH specific fields + console.log(`${pad}· L2 Token Bridge: ${chalk.underline(params.l2TokenBridge)}`); + console.log(`${pad}· L2 Token Non-Rebasable: ${chalk.underline(params.l2TokenNonRebasable)}`); +} + +export async function printMultiChainScratchDeploymentConfig( + title: string, + l1Deployer: Wallet, + l2Deployer: Wallet, + deploymentParams: MultiChainScratchDeploymentConfig, + l1DeployScript: DeployScript, + l2DeployScript: DeployScript, +) { + const { l1, l2 } = deploymentParams; + console.log(chalk.bold(`${title}\n`)); + + console.log(chalk.bold(" · Deployment Params:")); + await printDeploymentConfig(); + console.log(); + + console.log(chalk.bold(" · L1 Scratch Deployment Params:")); + await printL1ScratchConfig(l1Deployer, l1); + console.log(); + console.log(chalk.bold(" · L1 Deployment Actions:")); + l1DeployScript.print({ padding: 6 }); + + console.log(chalk.bold(" · L2 Scratch Deployment Params:")); + await printL2ScratchConfig(l2Deployer, l2); + console.log(); + console.log(chalk.bold(" · L2 Deployment Actions:")); + l2DeployScript.print({ padding: 6 }); +} + +async function printL1ScratchConfig( + deployer: Wallet, + params: L1ScratchDeploymentConfig +) { + const pad = " ".repeat(4); + const chainId = await deployer.getChainId(); + console.log(`${pad}· Chain ID: ${chainId}`); + console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); + + // Print base config with scratch deploy enabled + await printL1DeploymentConfig(deployer, params, true); + + // Print Scratch specific fields + console.log(`${pad}· Lido: ${chalk.underline(params.lido)}`); + console.log(`${pad}· Token Rate Notifier Owner: ${chalk.underline(params.tokenRateNotifierOwner)}`); +} + +async function printL2ScratchConfig( + deployer: Wallet, + params: L2ScratchDeploymentConfig +) { + const pad = " ".repeat(4); + const chainId = await deployer.getChainId(); + console.log(`${pad}· Chain ID: ${chainId}`); + console.log(`${pad}· Deployer: ${chalk.underline(deployer.address)}`); + + // Print base config with scratch deploy enabled + await printL2DeploymentConfig(deployer, params, true); +} + export default { loadMultiChainDeploymentConfig, + loadMultiChainStETHDeploymentConfig, + loadMultiChainScratchDeploymentConfig, printMultiChainDeploymentConfig, + printMultiChainStETHDeploymentConfig, + printMultiChainScratchDeploymentConfig, }; diff --git a/utils/deployment/DeployScript.ts b/utils/deployment/DeployScript.ts index 3e9f7b8c..0baa9e7e 100644 --- a/utils/deployment/DeployScript.ts +++ b/utils/deployment/DeployScript.ts @@ -8,6 +8,8 @@ import { Wallet, } from "ethers"; import network from "../network"; +import * as fs from 'fs'; +import env from "../../utils/env"; interface TypechainFactoryConstructor< T extends ContractFactory = ContractFactory @@ -56,6 +58,8 @@ export class DeployScript { private readonly steps: DeployStep[] = []; private contracts: Contract[] = []; public readonly deployer: Wallet; + private resultJson: { [key: string]: any } = {}; + public lastBlockNumber: number = 0; constructor(deployer: Wallet, logger?: Logger) { this.deployer = deployer; @@ -79,6 +83,14 @@ export class DeployScript { return res; } + async saveResultToFile(fileName: string) { + fs.writeFile(fileName, JSON.stringify(this.resultJson, null, 2), { encoding: "utf8", flag: "w" }, function(err) { + if (err) { + return console.error(err); + } + }); + } + print(printOptions?: PrintOptions) { for (let i = 0; i < this.steps.length; ++i) { this._printStepInfo(this._getStepInfo(i), { @@ -97,7 +109,8 @@ export class DeployScript { const contract = await new Factory(deployer).deploy(...step.args); const deployTx = contract.deployTransaction; this._log(`Waiting for tx: ${getBlockExplorerTxLinkByChainId(deployTx)}`); - await deployTx.wait(); + const receipt = await deployTx.wait(); + this.lastBlockNumber = receipt.blockNumber; this._log( `Contract ${chalk.yellow( factoryName @@ -109,10 +122,13 @@ export class DeployScript { if (step.afterDeploy) { step.afterDeploy(contract); } + const stepInfo = this._getStepInfo(index); await this._printVerificationCommand( contract.address, - this._getStepInfo(index) + stepInfo ); + const arsString = stepInfo.args.map((a) => `${a.value}`); + this.resultJson[contract.address] = arsString; return contract; } @@ -164,14 +180,7 @@ export class DeployScript { stepInfo: DeployStepInfo ) { const chainId = await this.deployer.getChainId(); - const networkNameByChainId: Record = { - 1: "eth_mainnet", - 11155111: "eth_sepolia", - 10: "opt_mainnet", - 11155420: "opt_sepolia", - 31337: "hardhat", - }; - const networkName = networkNameByChainId[chainId] || ""; + const networkName = this._networkNameByChainId(chainId); const arsString = stepInfo.args.map((a) => `"${a.value}"`).join(" "); this._log("To verify the contract on Etherscan, use command:"); this._log( @@ -182,6 +191,17 @@ export class DeployScript { private _log(message: string = "") { this.logger?.log(message); } + + private _networkNameByChainId(chainId: number): string { + switch (chainId) { + case env.number("L1_CHAIN_ID"): + return "l1"; + case env.number("L2_CHAIN_ID"): + return "l2"; + default: + throw new Error(`Unsupported chainId ${chainId}`) + } + } } function formatValue(value: string | number) { diff --git a/utils/env.ts b/utils/env.ts index 543af0b6..acbeb751 100644 --- a/utils/env.ts +++ b/utils/env.ts @@ -1,5 +1,4 @@ import { toAddress } from "@eth-optimism/sdk"; -import { NetworkName } from "./network"; function getString(variableName: string, defaultValue?: string) { const value = process.env[variableName]; @@ -47,26 +46,26 @@ function getAddressList(variableName: string, defaultValue?: string[]) { return getList(variableName, defaultValue).map(toAddress); } -function getNetwork(name: string = "NETWORK", defaultNetwork?: NetworkName) { - return getEnum(name, ["mainnet", "sepolia"], defaultNetwork); -} - function getPrivateKey() { - return getString("ETH_DEPLOYER_PRIVATE_KEY"); + return getString("L1_DEPLOYER_PRIVATE_KEY"); } function getForking() { return getBool("FORKING", false); } +function getNumber(variableName: string, defaultValue?: string) { + return Number(getString(variableName, defaultValue)); +} + export default { string: getString, + number: getNumber, list: getList, enum: getEnum, bool: getBool, address: getAddress, addresses: getAddressList, - network: getNetwork, privateKey: getPrivateKey, forking: getForking, }; diff --git a/utils/network.ts b/utils/network.ts index 30603cda..495296a5 100644 --- a/utils/network.ts +++ b/utils/network.ts @@ -6,32 +6,9 @@ import { HardhatRuntimeEnvironment, HttpNetworkConfig } from "hardhat/types"; import env from "./env"; -type ChainNameShort = "opt" | "eth"; -export type NetworkName = "sepolia" | "mainnet"; +type ChainNameShort = "l1" | "l2"; export type SignerOrProvider = Signer | Provider; -const HARDHAT_NETWORK_NAMES = { - eth: { - sepolia: "eth_sepolia", - mainnet: "eth_mainnet", - }, - opt: { - sepolia: "opt_sepolia", - mainnet: "opt_mainnet", - }, -}; - -const HARDHAT_NETWORK_NAMES_FORK = { - eth: { - sepolia: "eth_sepolia_fork", - mainnet: "eth_mainnet_fork", - }, - opt: { - sepolia: "opt_sepolia_fork", - mainnet: "opt_mainnet_fork", - }, -}; - export function getConfig(networkName: string, hre: HardhatRuntimeEnvironment) { const config = hre.config.networks[networkName]; if (!config) { @@ -72,77 +49,46 @@ function loadAccount(rpcURL: string, accountPrivateKeyName: string) { return new Wallet(privateKey, getProvider(rpcURL)); } -export function multichain( - chainNames: ChainNameShort[], - networkName: NetworkName -) { - return { - getNetworks(options: { forking: boolean }) { - const hardhatNetworkNames = options.forking - ? HARDHAT_NETWORK_NAMES_FORK - : HARDHAT_NETWORK_NAMES; +export function getProviders(options: { forking: boolean }) { + if (options.forking) { + return [getProvider(getConfig("l1_fork", hre).url), getProvider(getConfig("l2_fork", hre).url)]; + } + return [getProvider(getConfig("l1", hre).url), getProvider(getConfig("l2", hre).url)]; +} - const res: HttpNetworkConfig[] = []; - for (const chainName of chainNames) { - const hardhatNetworkName = hardhatNetworkNames[chainName][networkName]; - if (hardhatNetworkName === "NOT_DEPLOYED") { - throw new Error( - `Chain "${chainName}" doesn't support "${hardhatNetworkName}" network` - ); - } - res.push(getConfig(hardhatNetworkName, hre)); - } - return res; - }, - getProviders(options: { forking: boolean }) { - return this.getNetworks(options).map((network) => - getProvider(network.url) - ); - }, - getSigners(privateKey: string, options: { forking: boolean }) { - return this.getProviders(options).map( - (provider) => new Wallet(privateKey, provider) - ); - }, - }; +export function getSigners(privateKey: string, options: { forking: boolean }) { + return getProviders(options).map( + (provider) => new Wallet(privateKey, provider) + ); } -function getChainId(protocol: ChainNameShort, networkName: NetworkName) { - const chainIds = { - eth: { - mainnet: 1, - sepolia: 11155111, - }, - opt: { - mainnet: 10, - sepolia: 11155420, - }, - }; - const chainId = chainIds[protocol][networkName]; - if (!chainId) { - throw new Error(`Network for ${protocol} ${networkName} doesn't declared`); +function getChainId(protocol: ChainNameShort): number { + switch (protocol) { + case "l1": + return env.number("L1_CHAIN_ID"); + case "l2": + return env.number("L2_CHAIN_ID"); + default: + throw new Error(`Unsupported protocol ${protocol}`); } - return chainId; } -function getBlockExplorerBaseUrlByChainId(chainId: number) { - const baseUrlByChainId: Record = { - // ethereum - 1: "https://etherscan.io", - 11155111: "https://sepolia.etherscan.io", - // optimism - 10: "https://optimistic.etherscan.io", - 11155420: "https://blockscout.com/optimism/sepolia", - // forked node - 31337: "https://etherscan.io", - }; - return baseUrlByChainId[chainId]; +function getBlockExplorerBaseUrlByChainId(chainId: number): string { + switch (chainId) { + case env.number("L1_CHAIN_ID"): + return env.string("L1_BLOCK_EXPLORER_BROWSER_URL"); + case env.number("L2_CHAIN_ID"): + return env.string("L2_BLOCK_EXPLORER_BROWSER_URL"); + default: + throw new Error(`Unsupported chainId ${chainId}`); + } } export default { blockExplorerBaseUrl: getBlockExplorerBaseUrlByChainId, chainId: getChainId, - multichain, + getProviders, + getSigners, getConfig, getProvider, loadAccount, diff --git a/utils/optimism/addresses.ts b/utils/optimism/addresses.ts index 762cdb82..c5c565dc 100644 --- a/utils/optimism/addresses.ts +++ b/utils/optimism/addresses.ts @@ -1,26 +1,9 @@ -import { NetworkName } from "../network"; -import { OptContractAddresses, CommonOptions } from "./types"; +import env from "../env"; -const OptimismMainnetAddresses: OptContractAddresses = { - L1CrossDomainMessenger: "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", - L2CrossDomainMessenger: "0x4200000000000000000000000000000000000007" -}; - -const OptimismSepoliaAddresses: OptContractAddresses = { - L1CrossDomainMessenger: "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", - L2CrossDomainMessenger: "0x4200000000000000000000000000000000000007", -}; - -export default function addresses( - networkName: NetworkName, - options: CommonOptions = {} -) { - switch (networkName) { - case "mainnet": - return { ...OptimismMainnetAddresses, ...options.customAddresses }; - case "sepolia": - return { ...OptimismSepoliaAddresses, ...options.customAddresses }; - default: - throw new Error(`Network "${networkName}" is not supported`); - } +export default function addresses() { + return { + L1CrossDomainMessenger: env.string("L1_CROSSDOMAIN_MESSENGER", ""), + L2CrossDomainMessenger: env.string("L2_CROSSDOMAIN_MESSENGER", "") + }; } + diff --git a/utils/optimism/contracts.ts b/utils/optimism/contracts.ts index 4a7014db..6db61cb9 100644 --- a/utils/optimism/contracts.ts +++ b/utils/optimism/contracts.ts @@ -5,21 +5,19 @@ import { } from "../../typechain"; import addresses from "./addresses"; import { CommonOptions } from "./types"; -import network, { NetworkName } from "../network"; +import network from "../network"; interface ContractsOptions extends CommonOptions { forking: boolean; } export default function contracts( - networkName: NetworkName, options: ContractsOptions ) { const [l1Provider, l2Provider] = network - .multichain(["eth", "opt"], networkName) .getProviders(options); - const optAddresses = addresses(networkName, options); + const optAddresses = addresses(); return { L1CrossDomainMessenger: L1CrossDomainMessenger__factory.connect( diff --git a/utils/optimism/deployment.ts b/utils/optimism/deployAll.ts similarity index 64% rename from utils/optimism/deployment.ts rename to utils/optimism/deployAll.ts index b10add25..f5981ebd 100644 --- a/utils/optimism/deployment.ts +++ b/utils/optimism/deployAll.ts @@ -1,8 +1,7 @@ import { assert } from "chai"; import { BigNumber, Wallet } from "ethers"; -import addresses from "./addresses"; import { OptDeploymentOptions, DeployScriptParams } from "./types"; -import network, { NetworkName } from "../network"; +import network from "../network"; import { DeployScript, Logger } from "../deployment/DeployScript"; import { ERC20BridgedPermit__factory, @@ -11,20 +10,23 @@ import { L2ERC20ExtendedTokensBridge__factory, OssifiableProxy__factory, TokenRateOracle__factory, - TokenRateNotifier__factory, OpStackTokenRatePusher__factory, + TokenRateNotifier__factory, IERC20Metadata__factory } from "../../typechain"; interface OptL1DeployScriptParams extends DeployScriptParams { + l1CrossDomainMessenger: string; l1TokenNonRebasable: string; l1TokenRebasable: string; accountingOracle: string; l2GasLimitForPushingTokenRate: BigNumber; - lido: string; + lido?: string; + tokenRateNotifierOwner?: string; } interface OptL2DeployScriptParams extends DeployScriptParams { + l2CrossDomainMessenger: string; l2TokenNonRebasable: { name?: string; symbol?: string; @@ -38,6 +40,7 @@ interface OptL2DeployScriptParams extends DeployScriptParams { decimals?: number; }; tokenRateOracle: { + admin: string; tokenRateOutdatedDelay: BigNumber; maxAllowedL2ToL1ClockLag: BigNumber; maxAllowedTokenRateDeviationPerDayBp: BigNumber; @@ -45,17 +48,16 @@ interface OptL2DeployScriptParams extends DeployScriptParams { minTimeBetweenTokenRateUpdates: BigNumber; tokenRate: BigNumber; l1Timestamp: BigNumber; - } + }, } export class L1DeployAllScript extends DeployScript { - constructor( deployer: Wallet, bridgeImplAddress: string, bridgeProxyAddress: string, - tokenRateNotifierImplAddress: string, opStackTokenRatePusherImplAddress: string, + tokenRateNotifierImplAddress?: string, logger?: Logger ) { super(deployer, logger); @@ -67,7 +69,7 @@ export class L1DeployAllScript extends DeployScript { public bridgeImplAddress: string; public bridgeProxyAddress: string; - public tokenRateNotifierImplAddress: string; + public tokenRateNotifierImplAddress?: string; public opStackTokenRatePusherImplAddress: string; } @@ -106,72 +108,95 @@ export class L2DeployAllScript extends DeployScript { public tokenRateOracleProxyAddress: string; } -/// Deploy all from scratch -/// L1 part -/// L1LidoTokensBridge + Proxy -/// TokenRateNotifier -/// OpStackTokenRatePusher -/// L2 part -/// TokenRateOracle + Proxy -/// ERC20BridgedPermit + Proxy -/// ERC20RebasableBridgedPermit + Proxy -/// L2ERC20ExtendedTokensBridge + Proxy -export default function deploymentAll( - networkName: NetworkName, +async function predictAllAddresses(l1Params: OptL1DeployScriptParams, l2Params: OptL2DeployScriptParams, deployNotifier: boolean) { + const [ + l1TokenBridgeImpl, + l1TokenBridgeProxy, + l1OpStackTokenRatePusherImpl, + l1TokenRateNotifierImpl + ] = await network.predictAddresses(l1Params.deployer, l1Params.deployOffset + 3 + (deployNotifier ? 1 : 0)); + + const [ + l2TokenRateOracleImpl, + l2TokenRateOracleProxy, + l2TokenImpl, + l2TokenProxy, + l2TokenRebasableImpl, + l2TokenRebasableProxy, + l2TokenBridgeImpl, + l2TokenBridgeProxy + ] = await network.predictAddresses(l2Params.deployer, l2Params.deployOffset + 8); + + return { + l1TokenBridgeImpl, + l1TokenBridgeProxy, + l1OpStackTokenRatePusherImpl, + l1TokenRateNotifierImpl, + l2TokenRateOracleImpl, + l2TokenRateOracleProxy, + l2TokenImpl, + l2TokenProxy, + l2TokenRebasableImpl, + l2TokenRebasableProxy, + l2TokenBridgeImpl, + l2TokenBridgeProxy + }; +} + +/// Deploy all contracts on new network from scratch. +export default function deployAll( + deployNotifier: boolean, options: OptDeploymentOptions = {} ) { - const optAddresses = addresses(networkName, options); return { async deployAllScript( l1Params: OptL1DeployScriptParams, l2Params: OptL2DeployScriptParams, ): Promise<[L1DeployAllScript, L2DeployAllScript]> { + let predictedAddresses = await predictAllAddresses(l1Params, l2Params, deployNotifier); + let numClashedAddresses = Object.keys(predictedAddresses).length - new Set(Object.values(predictedAddresses)).size; - const [ - expectedL1TokenBridgeImplAddress, - expectedL1TokenBridgeProxyAddress, - expectedL1TokenRateNotifierImplAddress, - expectedL1OpStackTokenRatePusherImplAddress, - ] = await network.predictAddresses(l1Params.deployer, l1Params.deployOffset + 4); - - const [ - expectedL2TokenRateOracleImplAddress, - expectedL2TokenRateOracleProxyAddress, - expectedL2TokenImplAddress, - expectedL2TokenProxyAddress, - expectedL2TokenRebasableImplAddress, - expectedL2TokenRebasableProxyAddress, - expectedL2TokenBridgeImplAddress, - expectedL2TokenBridgeProxyAddress - ] = await network.predictAddresses(l2Params.deployer, l2Params.deployOffset + 8); + // Burning enough nonces on L2 side + while (numClashedAddresses > 0) { + console.log(`NB: Num of clashed predicted addresses on L1 and L2: ${numClashedAddresses}. Burning ${numClashedAddresses} nonces on L2 side...`); + for (let i = 0; i < numClashedAddresses; i++) { + const tx = await l2Params.deployer.sendTransaction({ + to: l2Params.deployer.address, + value: 0 + }); + await tx.wait() + } + predictedAddresses = await predictAllAddresses(l1Params, l2Params, deployNotifier); + numClashedAddresses = Object.keys(predictedAddresses).length - new Set(Object.values(predictedAddresses)).size; + } const l1DeployScript = new L1DeployAllScript( l1Params.deployer, - expectedL1TokenBridgeImplAddress, - expectedL1TokenBridgeProxyAddress, - expectedL1TokenRateNotifierImplAddress, - expectedL1OpStackTokenRatePusherImplAddress, + predictedAddresses.l1TokenBridgeImpl, + predictedAddresses.l1TokenBridgeProxy, + predictedAddresses.l1OpStackTokenRatePusherImpl, + predictedAddresses.l1TokenRateNotifierImpl, options?.logger ) .addStep({ factory: L1LidoTokensBridge__factory, args: [ - optAddresses.L1CrossDomainMessenger, - expectedL2TokenBridgeProxyAddress, + l1Params.l1CrossDomainMessenger, + predictedAddresses.l2TokenBridgeProxy, l1Params.l1TokenNonRebasable, l1Params.l1TokenRebasable, - expectedL2TokenProxyAddress, - expectedL2TokenRebasableProxyAddress, + predictedAddresses.l2TokenProxy, + predictedAddresses.l2TokenRebasableProxy, l1Params.accountingOracle, options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL1TokenBridgeImplAddress), + assert.equal(c.address, predictedAddresses.l1TokenBridgeImpl), }) .addStep({ factory: OssifiableProxy__factory, args: [ - expectedL1TokenBridgeImplAddress, + predictedAddresses.l1TokenBridgeImpl, l1Params.admins.proxy, L1LidoTokensBridge__factory.createInterface().encodeFunctionData( "initialize", @@ -180,32 +205,35 @@ export default function deploymentAll( options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL1TokenBridgeProxyAddress), - }) - .addStep({ - factory: TokenRateNotifier__factory, - args: [ - l1Params.deployer.address, - l1Params.lido, - options?.overrides, - ], - afterDeploy: (c) => - assert.equal(c.address, expectedL1TokenRateNotifierImplAddress), + assert.equal(c.address, predictedAddresses.l1TokenBridgeProxy), }) .addStep({ factory: OpStackTokenRatePusher__factory, args: [ - optAddresses.L1CrossDomainMessenger, + l1Params.l1CrossDomainMessenger, l1Params.l1TokenNonRebasable, l1Params.accountingOracle, - expectedL2TokenRateOracleProxyAddress, + predictedAddresses.l2TokenRateOracleProxy, l1Params.l2GasLimitForPushingTokenRate, options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL1OpStackTokenRatePusherImplAddress), + assert.equal(c.address, predictedAddresses.l1OpStackTokenRatePusherImpl), }); + if (deployNotifier && l1Params.tokenRateNotifierOwner && l1Params.lido) { + l1DeployScript.addStep({ + factory: TokenRateNotifier__factory, + args: [ + l1Params.tokenRateNotifierOwner, + l1Params.lido, + options?.overrides, + ], + afterDeploy: (c) => + assert.equal(c.address, predictedAddresses.l1TokenRateNotifierImpl), + }) + } + const l1TokenNonRebasableInfo = IERC20Metadata__factory.connect( l1Params.l1TokenNonRebasable, l1Params.deployer @@ -230,22 +258,22 @@ export default function deploymentAll( const l2DeployScript = new L2DeployAllScript( l2Params.deployer, - expectedL2TokenImplAddress, - expectedL2TokenProxyAddress, - expectedL2TokenRebasableImplAddress, - expectedL2TokenRebasableProxyAddress, - expectedL2TokenBridgeImplAddress, - expectedL2TokenBridgeProxyAddress, - expectedL2TokenRateOracleImplAddress, - expectedL2TokenRateOracleProxyAddress, + predictedAddresses.l2TokenImpl, + predictedAddresses.l2TokenProxy, + predictedAddresses.l2TokenRebasableImpl, + predictedAddresses.l2TokenRebasableProxy, + predictedAddresses.l2TokenBridgeImpl, + predictedAddresses.l2TokenBridgeProxy, + predictedAddresses.l2TokenRateOracleImpl, + predictedAddresses.l2TokenRateOracleProxy, options?.logger ) .addStep({ factory: TokenRateOracle__factory, args: [ - optAddresses.L2CrossDomainMessenger, - expectedL2TokenBridgeProxyAddress, - expectedL1OpStackTokenRatePusherImplAddress, + l2Params.l2CrossDomainMessenger, + predictedAddresses.l2TokenBridgeProxy, + predictedAddresses.l1OpStackTokenRatePusherImpl, l2Params.tokenRateOracle.tokenRateOutdatedDelay, l2Params.tokenRateOracle.maxAllowedL2ToL1ClockLag, l2Params.tokenRateOracle.maxAllowedTokenRateDeviationPerDayBp, @@ -254,17 +282,17 @@ export default function deploymentAll( options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenRateOracleImplAddress), + assert.equal(c.address, predictedAddresses.l2TokenRateOracleImpl), }) .addStep({ factory: OssifiableProxy__factory, args: [ - expectedL2TokenRateOracleImplAddress, + predictedAddresses.l2TokenRateOracleImpl, l2Params.admins.proxy, TokenRateOracle__factory.createInterface().encodeFunctionData( "initialize", [ - l2Params.admins.bridge, + l2Params.tokenRateOracle.admin, l2Params.tokenRateOracle.tokenRate, l2Params.tokenRateOracle.l1Timestamp ] @@ -272,7 +300,7 @@ export default function deploymentAll( options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenRateOracleProxyAddress), + assert.equal(c.address, predictedAddresses.l2TokenRateOracleProxy), }) .addStep({ factory: ERC20BridgedPermit__factory, @@ -281,16 +309,16 @@ export default function deploymentAll( l2TokenNonRebasableSymbol, l2Params.l2TokenNonRebasable.version, l2TokenNonRebasableDecimals, - expectedL2TokenBridgeProxyAddress, + predictedAddresses.l2TokenBridgeProxy, options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenImplAddress), + assert.equal(c.address, predictedAddresses.l2TokenImpl), }) .addStep({ factory: OssifiableProxy__factory, args: [ - expectedL2TokenImplAddress, + predictedAddresses.l2TokenImpl, l2Params.admins.proxy, ERC20BridgedPermit__factory.createInterface().encodeFunctionData( "initialize", @@ -303,7 +331,7 @@ export default function deploymentAll( options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenProxyAddress), + assert.equal(c.address, predictedAddresses.l2TokenProxy), }) .addStep({ factory: ERC20RebasableBridgedPermit__factory, @@ -312,18 +340,18 @@ export default function deploymentAll( l2TokenRebasableSymbol, l2Params.l2TokenRebasable.version, l2TokenRebasableDecimals, - expectedL2TokenProxyAddress, - expectedL2TokenRateOracleProxyAddress, - expectedL2TokenBridgeProxyAddress, + predictedAddresses.l2TokenProxy, + predictedAddresses.l2TokenRateOracleProxy, + predictedAddresses.l2TokenBridgeProxy, options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenRebasableImplAddress), + assert.equal(c.address, predictedAddresses.l2TokenRebasableImpl), }) .addStep({ factory: OssifiableProxy__factory, args: [ - expectedL2TokenRebasableImplAddress, + predictedAddresses.l2TokenRebasableImpl, l2Params.admins.proxy, ERC20RebasableBridgedPermit__factory.createInterface().encodeFunctionData( "initialize", @@ -336,26 +364,26 @@ export default function deploymentAll( options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenRebasableProxyAddress), + assert.equal(c.address, predictedAddresses.l2TokenRebasableProxy), }) .addStep({ factory: L2ERC20ExtendedTokensBridge__factory, args: [ - optAddresses.L2CrossDomainMessenger, - expectedL1TokenBridgeProxyAddress, + l2Params.l2CrossDomainMessenger, + predictedAddresses.l1TokenBridgeProxy, l1Params.l1TokenNonRebasable, l1Params.l1TokenRebasable, - expectedL2TokenProxyAddress, - expectedL2TokenRebasableProxyAddress, + predictedAddresses.l2TokenProxy, + predictedAddresses.l2TokenRebasableProxy, options?.overrides, ], afterDeploy: (c) => - assert.equal(c.address, expectedL2TokenBridgeImplAddress), + assert.equal(c.address, predictedAddresses.l2TokenBridgeImpl), }) .addStep({ factory: OssifiableProxy__factory, args: [ - expectedL2TokenBridgeImplAddress, + predictedAddresses.l2TokenBridgeImpl, l2Params.admins.proxy, L2ERC20ExtendedTokensBridge__factory.createInterface().encodeFunctionData( "initialize", diff --git a/utils/optimism/deploymentOracle.ts b/utils/optimism/deployOracle.ts similarity index 96% rename from utils/optimism/deploymentOracle.ts rename to utils/optimism/deployOracle.ts index ffec038e..09f8fc89 100644 --- a/utils/optimism/deploymentOracle.ts +++ b/utils/optimism/deployOracle.ts @@ -1,9 +1,8 @@ import { assert } from "chai"; import { BigNumber, Wallet } from "ethers"; -import { ethers } from "hardhat"; -import addresses from "./addresses"; import { DeployScriptParams, OptDeploymentOptions } from "./types"; -import network, { NetworkName } from "../network"; +import addresses from "./addresses"; +import network from "../network"; import { DeployScript, Logger } from "../deployment/DeployScript"; import { OssifiableProxy__factory, @@ -71,10 +70,9 @@ export class OracleL2DeployScript extends DeployScript { /// L2 part /// TokenRateOracle + proxy export default function deploymentOracle( - networkName: NetworkName, options: OptDeploymentOptions = {} ) { - const optAddresses = addresses(networkName, options); + const optAddresses = addresses(); return { async oracleDeployScript( l1Params: OptL1DeployScriptParams, diff --git a/utils/optimism/deploymentStETH.ts b/utils/optimism/deployStETH.ts similarity index 90% rename from utils/optimism/deploymentStETH.ts rename to utils/optimism/deployStETH.ts index e7e6fc2e..9b1e09b0 100644 --- a/utils/optimism/deploymentStETH.ts +++ b/utils/optimism/deployStETH.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { BigNumber, Wallet } from "ethers"; import addresses from "./addresses"; import { OptDeploymentOptions, DeployScriptParams } from "./types"; -import network, { NetworkName } from "../network"; +import network from "../network"; import { DeployScript, Logger } from "../deployment/DeployScript"; import { ERC20BridgedPermit__factory, @@ -17,44 +17,42 @@ import { } from "../../typechain"; interface OptL1UpgradeScriptParams extends DeployScriptParams { + l1CrossDomainMessenger: string; l1TokenNonRebasable: string; l1TokenRebasable: string; accountingOracle: string; l2GasLimitForPushingTokenRate: BigNumber; l1TokenBridge: string; lido: string; + tokenRateNotifierOwner: string; } interface OptL2UpgradeScriptParams extends DeployScriptParams { + l2CrossDomainMessenger: string; l2TokenBridge: string; l2TokenNonRebasable: { address: string; + version: string; name?: string; symbol?: string; - version: string; decimals?: BigNumber; }; l2TokenRebasable: { proxyAdmin: string; + version: string; name?: string; symbol?: string; - version: string; decimals?: BigNumber; }; tokenRateOracle: { - proxyAdmin: string; admin: string; - constructor: { - tokenRateOutdatedDelay: BigNumber; - maxAllowedL2ToL1ClockLag: BigNumber; - maxAllowedTokenRateDeviationPerDayBp: BigNumber; - oldestRateAllowedInPauseTimeSpan: BigNumber; - minTimeBetweenTokenRateUpdates: BigNumber; - } - initialize: { - tokenRate: BigNumber; - l1Timestamp: BigNumber; - } + tokenRateOutdatedDelay: BigNumber; + maxAllowedL2ToL1ClockLag: BigNumber; + maxAllowedTokenRateDeviationPerDayBp: BigNumber; + oldestRateAllowedInPauseTimeSpan: BigNumber; + minTimeBetweenTokenRateUpdates: BigNumber; + tokenRate: BigNumber; + l1Timestamp: BigNumber; } } @@ -125,10 +123,9 @@ export class L2UpgradeScript extends DeployScript { /// Non-rebasable token (wstETH) new Impl with Permissions export default function deploy( - networkName: NetworkName, options: OptDeploymentOptions = {} ) { - const optAddresses = addresses(networkName, options); + const optAddresses = addresses(); return { async deployScript( l1Params: OptL1UpgradeScriptParams, @@ -180,7 +177,7 @@ export default function deploy( .addStep({ factory: TokenRateNotifier__factory, args: [ - l1Params.deployer.address, + l1Params.tokenRateNotifierOwner, l1Params.lido, options?.overrides, ], @@ -239,11 +236,11 @@ export default function deploy( optAddresses.L2CrossDomainMessenger, l2Params.l2TokenBridge, expectedL1OpStackTokenRatePusherImplAddress, - l2Params.tokenRateOracle.constructor.tokenRateOutdatedDelay, - l2Params.tokenRateOracle.constructor.maxAllowedL2ToL1ClockLag, - l2Params.tokenRateOracle.constructor.maxAllowedTokenRateDeviationPerDayBp, - l2Params.tokenRateOracle.constructor.oldestRateAllowedInPauseTimeSpan, - l2Params.tokenRateOracle.constructor.minTimeBetweenTokenRateUpdates, + l2Params.tokenRateOracle.tokenRateOutdatedDelay, + l2Params.tokenRateOracle.maxAllowedL2ToL1ClockLag, + l2Params.tokenRateOracle.maxAllowedTokenRateDeviationPerDayBp, + l2Params.tokenRateOracle.oldestRateAllowedInPauseTimeSpan, + l2Params.tokenRateOracle.minTimeBetweenTokenRateUpdates, options?.overrides, ], afterDeploy: (c) => @@ -253,13 +250,13 @@ export default function deploy( factory: OssifiableProxy__factory, args: [ expectedL2TokenRateOracleImplAddress, - l2Params.tokenRateOracle.proxyAdmin, + l2Params.admins.proxy, TokenRateOracle__factory.createInterface().encodeFunctionData( "initialize", [ l2Params.tokenRateOracle.admin, - l2Params.tokenRateOracle.initialize.tokenRate, - l2Params.tokenRateOracle.initialize.l1Timestamp + l2Params.tokenRateOracle.tokenRate, + l2Params.tokenRateOracle.l1Timestamp ] ), options?.overrides, diff --git a/utils/optimism/messaging.ts b/utils/optimism/messaging.ts index 6724d447..0586dab8 100644 --- a/utils/optimism/messaging.ts +++ b/utils/optimism/messaging.ts @@ -1,5 +1,5 @@ import contracts from "./contracts"; -import network, { NetworkName } from "../network"; +import network from "../network"; import { CommonOptions } from "./types"; import { CrossChainMessenger, MessageStatus } from "@eth-optimism/sdk"; @@ -15,19 +15,17 @@ interface MessageData { } export default function messaging( - networkName: NetworkName, options: ContractsOptions ) { const [ethProvider, optProvider] = network - .multichain(["eth", "opt"], networkName) .getProviders(options); - const optContracts = contracts(networkName, options); + const optContracts = contracts(options); const crossChainMessenger = new CrossChainMessenger({ - l2ChainId: network.chainId("opt", networkName), + l1ChainId: network.chainId("l1"), + l2ChainId: network.chainId("l2"), l1SignerOrProvider: ethProvider, l2SignerOrProvider: optProvider, - l1ChainId: network.chainId("eth", networkName), }); return { prepareL2Message(msg: MessageData) { diff --git a/utils/optimism/testing.ts b/utils/optimism/testing.ts index 0e97bcd4..d64b3760 100644 --- a/utils/optimism/testing.ts +++ b/utils/optimism/testing.ts @@ -16,22 +16,22 @@ import { ERC20RebasableBridgedPermit__factory, AccountingOracleStub__factory, TokenRateNotifier__factory, - StETHStub__factory + StETHStub__factory, + OpStackTokenRatePusher__factory } from "../../typechain"; import addresses from "./addresses"; import contracts from "./contracts"; -import deploymentAll from "./deployment"; +import deployAll from "./deployAll"; import testingUtils from "../testing"; import { BridgingManagement } from "../bridging-management"; -import network, { NetworkName, SignerOrProvider } from "../network"; +import network, { SignerOrProvider } from "../network"; -export default function testing(networkName: NetworkName) { - const optAddresses = addresses(networkName); - const ethOptNetworks = network.multichain(["eth", "opt"], networkName); +export default function testing() { + const optAddresses = addresses(); return { async getAcceptanceTestSetup() { - const [ethProvider, optProvider] = ethOptNetworks.getProviders({ + const [ethProvider, optProvider] = network.getProviders({ forking: true, }); @@ -40,7 +40,7 @@ export default function testing(networkName: NetworkName) { optProvider ); - await printLoadedTestConfig(networkName, bridgeContracts); + await printLoadedTestConfig(bridgeContracts); return { l1Provider: ethProvider, @@ -50,14 +50,14 @@ export default function testing(networkName: NetworkName) { }, async getIntegrationTestSetup() { const hasDeployedContracts = testingUtils.env.USE_DEPLOYED_CONTRACTS(false); - const [ethProvider, optProvider] = ethOptNetworks.getProviders({ forking: true }); + const [ethProvider, optProvider] = network.getProviders({ forking: true }); var totalPooledEther = BigNumber.from('9309904612343950493629678'); var totalShares = BigNumber.from('7975822843597609202337218'); const bridgeContracts = hasDeployedContracts ? await loadDeployedBridges(ethProvider, optProvider) - : await deployTestBridge(networkName, totalPooledEther, totalShares, ethProvider, optProvider); + : await deployTestBridge(totalPooledEther, totalShares, ethProvider, optProvider); if (hasDeployedContracts) { totalPooledEther = await bridgeContracts.l1TokenRebasable.getTotalPooledEther(); @@ -79,13 +79,12 @@ export default function testing(networkName: NetworkName) { if (hasDeployedContracts) { await printLoadedTestConfig( - networkName, bridgeContracts, l1TokensHolder ); } - const optContracts = contracts(networkName, { forking: true }); + const optContracts = contracts({ forking: true }); return { totalPooledEther: totalPooledEther, @@ -108,16 +107,16 @@ export default function testing(networkName: NetworkName) { }, async getE2ETestSetup() { const testerPrivateKey = testingUtils.env.TESTING_PRIVATE_KEY(); - const [ethProvider, optProvider] = ethOptNetworks.getProviders({ + const [ethProvider, optProvider] = network.getProviders({ forking: false, }); - const [l1Tester, l2Tester] = ethOptNetworks.getSigners(testerPrivateKey, { + const [l1Tester, l2Tester] = network.getSigners(testerPrivateKey, { forking: false, }); const bridgeContracts = await loadDeployedBridges(l1Tester, l2Tester); - await printLoadedTestConfig(networkName, bridgeContracts, l1Tester); + await printLoadedTestConfig(bridgeContracts, l1Tester); return { l1Tester, @@ -128,13 +127,14 @@ export default function testing(networkName: NetworkName) { }; }, async stubL1CrossChainMessengerContract() { - const [ethProvider] = ethOptNetworks.getProviders({ forking: true }); + const [ethProvider] = network.getProviders({ forking: true }); const deployer = testingUtils.accounts.deployer(ethProvider); const stub = await new CrossDomainMessengerStub__factory( deployer ).deploy(); const stubBytecode = await ethProvider.send("eth_getCode", [ stub.address, + "latest" ]); await ethProvider.send("hardhat_setCode", [ @@ -166,6 +166,7 @@ async function loadDeployedBridges( ...connectBridgeContracts( { tokenRateNotifier: testingUtils.env.OPT_L1_TOKEN_RATE_NOTIFIER(), + opStackTokenRatePusher: testingUtils.env.OPT_L1_OP_STACK_TOKEN_RATE_PUSHER(), tokenRateOracle: testingUtils.env.OPT_L2_TOKEN_RATE_ORACLE(), l2Token: testingUtils.env.OPT_L2_NON_REBASABLE_TOKEN(), l2TokenRebasable: testingUtils.env.OPT_L2_REBASABLE_TOKEN(), @@ -179,7 +180,6 @@ async function loadDeployedBridges( } async function deployTestBridge( - networkName: NetworkName, totalPooledEther: BigNumber, totalShares: BigNumber, ethProvider: JsonRpcProvider, @@ -232,6 +232,11 @@ async function deployTestBridge( const ethDeployer = testingUtils.accounts.deployer(ethProvider); const optDeployer = testingUtils.accounts.deployer(optProvider); + const crossDomainAddresses = addresses(); + if (!crossDomainAddresses.L1CrossDomainMessenger || !crossDomainAddresses.L2CrossDomainMessenger) { + throw new Error('CrossDomainMessenger addresses are not defined'); + } + const l1TokenRebasable = await new StETHStub__factory(ethDeployer).deploy( l1TokenRebasableName, l1TokenRebasableSymbol @@ -251,15 +256,15 @@ async function deployTestBridge( lastProcessingRefSlot ); - const [ethDeployScript, optDeployScript] = await deploymentAll( - networkName - ).deployAllScript( + const [ethDeployScript, optDeployScript] = await deployAll(true) + .deployAllScript( { l1TokenNonRebasable: l1TokenNonRebasable.address, l1TokenRebasable: l1TokenRebasable.address, accountingOracle: accountingOracle.address, l2GasLimitForPushingTokenRate: l2GasLimitForPushingTokenRate, lido: lido, + l1CrossDomainMessenger: crossDomainAddresses.L1CrossDomainMessenger, deployer: ethDeployer, admins: { proxy: ethDeployer.address, bridge: ethDeployer.address }, @@ -267,6 +272,7 @@ async function deployTestBridge( }, { tokenRateOracle: { + admin: optDeployer.address, tokenRateOutdatedDelay: tokenRateOutdatedDelay, maxAllowedL2ToL1ClockLag: maxAllowedL2ToL1ClockLag, maxAllowedTokenRateDeviationPerDayBp: maxAllowedTokenRateDeviationPerDay, @@ -275,6 +281,7 @@ async function deployTestBridge( tokenRate: tokenRate, l1Timestamp: l1TokenRateUpdate }, + l2CrossDomainMessenger: crossDomainAddresses.L2CrossDomainMessenger, l2TokenNonRebasable: { name: l2TokenNonRebasable.name, symbol: l2TokenNonRebasable.symbol, @@ -297,6 +304,10 @@ async function deployTestBridge( await ethDeployScript.run(); await optDeployScript.run(); + if (!ethDeployScript.tokenRateNotifierImplAddress || !ethDeployScript.opStackTokenRatePusherImplAddress) { + throw new Error('Token rate notifier addresses are not defined'); + } + const tokenRateNotifier = TokenRateNotifier__factory.connect( ethDeployScript.tokenRateNotifierImplAddress, ethProvider @@ -334,6 +345,7 @@ async function deployTestBridge( ...connectBridgeContracts( { tokenRateNotifier: ethDeployScript.tokenRateNotifierImplAddress, + opStackTokenRatePusher: ethDeployScript.opStackTokenRatePusherImplAddress, tokenRateOracle: optDeployScript.tokenRateOracleProxyAddress, l2Token: optDeployScript.tokenProxyAddress, l2TokenRebasable: optDeployScript.tokenRebasableProxyAddress, @@ -349,6 +361,7 @@ async function deployTestBridge( function connectBridgeContracts( addresses: { tokenRateNotifier: string; + opStackTokenRatePusher: string; tokenRateOracle: string; l2Token: string; l2TokenRebasable: string; @@ -362,6 +375,10 @@ function connectBridgeContracts( addresses.tokenRateNotifier, ethSignerOrProvider ); + const opStackTokenRatePusher = OpStackTokenRatePusher__factory.connect( + addresses.opStackTokenRatePusher, + ethSignerOrProvider + ); const l1LidoTokensBridge = L1LidoTokensBridge__factory.connect( addresses.l1LidoTokensBridge, ethSignerOrProvider @@ -384,6 +401,7 @@ function connectBridgeContracts( ); return { tokenRateNotifier, + opStackTokenRatePusher, tokenRateOracle, l2Token, l2TokenRebasable, @@ -393,7 +411,6 @@ function connectBridgeContracts( } async function printLoadedTestConfig( - networkName: NetworkName, bridgeContracts: { l1Token: IERC20; l1TokenRebasable: IERC20; @@ -407,7 +424,7 @@ async function printLoadedTestConfig( console.log( "In case of unexpected fails, please, make sure that you are forking correct Ethereum/Optimism networks" ); - console.log(` · Network Name: ${networkName}`); + //console.log(` · Network Id: ${networkName}`); console.log(` · L1 Token: ${bridgeContracts.l1Token.address}`); console.log(` · L2 Token: ${bridgeContracts.l2Token.address}`); if (l1TokensHolder) { diff --git a/utils/optimism/types.ts b/utils/optimism/types.ts index af736ad9..37a5cafe 100644 --- a/utils/optimism/types.ts +++ b/utils/optimism/types.ts @@ -15,7 +15,7 @@ export interface DeployScriptParams { deployer: Wallet; admins: { proxy: string; - bridge: string + bridge: string; }; deployOffset: number; } diff --git a/utils/prompt.ts b/utils/prompt.ts index 90ce0868..cfaa4af2 100644 --- a/utils/prompt.ts +++ b/utils/prompt.ts @@ -17,6 +17,10 @@ function prompt(question: string, availableAnswers?: string[]) { } async function promptProceed() { + if (process.env.L2_DEPLOY_SKIP_PROMPTS) { + return; + } + const positiveAnswers = ["y", "yes"]; const negativeAnswers = ["n", "no"]; const answer = await prompt("Do you want to proceed? [yes/no]", [ diff --git a/utils/testing/env.ts b/utils/testing/env.ts index 69dd135b..877f27e7 100644 --- a/utils/testing/env.ts +++ b/utils/testing/env.ts @@ -34,6 +34,9 @@ export default { OPT_L1_TOKEN_RATE_NOTIFIER() { return env.address("TESTING_OPT_L1_TOKEN_RATE_NOTIFIER"); }, + OPT_L1_OP_STACK_TOKEN_RATE_PUSHER() { + return env.address("TESTING_OPT_L1_OP_STACK_TOKEN_RATE_PUSHER"); + }, OPT_GOV_BRIDGE_EXECUTOR() { return env.address("TESTING_OPT_GOV_BRIDGE_EXECUTOR"); },