Commit da9ddd77 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #6127 from ethereum-optimism/cleanup/remove-hh-deploy

contracts-bedrock: delete hh deploy scripts
parents 759473bb d82e0af3
......@@ -33,6 +33,8 @@ You’ll need the following software installed to follow this tutorial:
- [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/)
- [Foundry](https://github.com/foundry-rs/foundry#installation)
- [Make](https://linux.die.net/man/1/make)
- [jq](https://github.com/jqlang/jq)
- [direnv](https://direnv.net)
This tutorial was checked on:
......@@ -126,28 +128,38 @@ You can generate all of these keys with the `rekey` tool in the `contracts-bedro
cd packages/contracts-bedrock
```
1. Run the `rekey` command:
1. Use `cast wallet` to generate new accounts
```bash
npx hardhat rekey
echo "Admin:"
cast wallet new
echo "Proposer:"
cast wallet new
echo "Batcher:"
cast wallet new
echo "Sequencer:"
cast wallet new
```
You should get an output like the following:
```
Mnemonic: barely tongue excite actor edge huge lion employ gauge despair this learn
Admin: 0x301c314ca0eedf88a5f7a44680d9dccceb8fcbea
Private Key: ef06ba0291b6e2fa336fd9c06de9c2f18f72ed17cd4fcbda7b376f10592b43d8
Proposer: 0x54355b7d195fcdea96696a522c444c185afaf1a8
Private Key: 8bf67a8cd20087472db00fd869a0ffd7574a4481fb2a07a5f5c6bfb46dcb09ca
Batcher: 0x9a686086e3c74ddd5b59b710b26a73407d9c7e97
Private Key: 1533b607f668cce9553cafbfdfe9529eb31d67f1958d4b16fbdf857a8c50dd56
Sequencer: 0x0324a4c8c1955cb8364e8f07558238b3d2aa5f55
Private Key: fba31658f320bb8ce1ce39fab3c7c2acea6b4dd69cc8483fd85388a461d8426b
Admin:
Successfully created new keypair.
Address: 0x9f92bdF0db69264462FC305913960Edfcc7a7c7F
Private key: 0x30e66956e1a12b81f0f2cfb982286b2f566eb73649833831d9f80b12f8fa183c
Proposer:
Successfully created new keypair.
Address: 0x31dE9B6473fc47af36ec23878bA34824B9F4AB30
Private key: 0x8bd1c8dfffef880f8f9ab8162f97ccd119c1aac28fe00dacf919459f88e0f37d
Batcher:
Successfully created new keypair.
Address: 0x6A3DC843843139f17Fcf04C057bb536A421DC9c6
Private key: 0x3ce44144b7fde797a28f4e47b210a4d42c3a3b642e538b54458cba2740db5ac2
Sequencer:
Successfully created new keypair.
Address: 0x98C6cadB1fe77aBB7bD968fC3E9b206111e72848
Private key: 0x3f4241229bb6f155140d98e0f5dd2aad7ae983f5af5d61555d05eb8e5d9514db
```
Save these accounts and their respective private keys somewhere, you’ll need them later. Fund the `Admin` address with a small amount of Goerli ETH as we’ll use that account to deploy our smart contracts. You’ll also need to fund the `Proposer` and `Batcher` address — note that the `Batcher` burns through the most ETH because it publishes transaction data to L1.
......@@ -160,7 +172,7 @@ Recommended funding amounts are as follows:
::: danger Not for production deployments
The `rekey` tool is *not* designed for production deployments. If you are deploying an OP Stack based chain into production, you should likely be using a combination of hardware security modules and hardware wallets.
The `cast wallet` tool is *not* designed for production deployments. If you are deploying an OP Stack based chain into production, you should likely be using a combination of hardware security modules and hardware wallets.
:::
......@@ -180,10 +192,28 @@ Once you’ve built both repositories, you’ll need head back to the Optimism M
cd packages/contracts-bedrock
```
1. Inside of `contracts-bedrock`, copy the environment file
```sh
cp .envrc.example .envrc
```
1. Fill out the environment variables inside of that file:
- `ETH_RPC_URL` — URL for your L1 node.
- `PRIVATE_KEY` — Private key of the `Admin` account.
- `DEPLOYMENT_CONTEXT` - Name of the network, should be "getting-started"
1. Pull the environment variables into context using `direnv`
```bash
direnv allow .
```
1. Before we can create our configuration file, we’ll need to pick an L1 block to serve as the starting point for our Rollup. It’s best to use a finalized L1 block as our starting block. You can use the `cast` command provided by Foundry to grab all of the necessary information (replace `<RPC>` with the URL for your L1 Goerli node):
```bash
cast block finalized --rpc-url <RPC> | grep -E "(timestamp|hash|number)"
cast block finalized --rpc-url $ETH_RPC_URL | grep -E "(timestamp|hash|number)"
```
You’ll get back something that looks like the following:
......@@ -207,21 +237,11 @@ Once you’ve built both repositories, you’ll need head back to the Optimism M
Once you’ve configured your network, it’s time to deploy the L1 smart contracts necessary for the functionality of the chain.
1. Inside of `contracts-bedrock`, copy `.env.example` to `.env`.
```sh
cp .env.example .env
```
1. Fill out the two environment variables inside of that file:
- `L1_RPC` — URL for your L1 node.
- `PRIVATE_KEY_DEPLOYER` — Private key of the `Admin` account.
1. Once you’re ready, deploy the L1 smart contracts:
```bash
npx hardhat deploy --network getting-started --tags l1
forge script scripts/Deploy.s.sol:Deploy --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
forge script scripts/Deploy.s.sol:Deploy --sig 'sync()' --private-key $PRIVATE_KEY --broadcast --rpc-url $ETH_RPC_URL
```
Contract deployment can take up to 15 minutes. Please wait for all smart contracts to be fully deployed before continuing to the next step.
......
# RPC for the L1 network to deploy to
L1_RPC=
# Private key for the deployer account
PRIVATE_KEY_DEPLOYER=
# Optional Tenderly details for a simulation link during deployment
TENDERLY_PROJECT=
TENDERLY_USERNAME=
# The following settings are useful for manually testing the migration scripts.
# Define if cast commands should be printed.
CAST_COMMANDS=1
# Saves deployment artifacts when using the 'live' network
SAVE_DEPLOYMENTS=1
# Disable the live deployer so that transactions must be submitted manually
DISABLE_LIVE_DEPLOYER=true
# Sets the deployer's key to match the first default hardhat account
PRIVATE_KEY_DEPLOYER=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# RPC for the network to deploy to
export ETH_RPC_URL=
# Sets the deployer's key to match the first default hardhat account
export PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# Name of the deployed network
export DEPLOYMENT_CONTEXT=getting-started
# Optional Tenderly details for a simulation link during deployment
export TENDERLY_PROJECT=
export TENDERLY_USERNAME=
......@@ -16,3 +16,6 @@ scripts/differential-testing/differential-testing
deployments/900
deployments/901
deployments/hardhat
.envrc
!.envrc.example
deployments/getting-started
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
await deploy({
hre,
name: 'Lib_AddressManager',
contract: 'AddressManager',
args: [],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'owner', deployer)
},
})
}
deployFn.tags = ['AddressManager', 'setup', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
getContractsFromArtifacts,
deploy,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [addressManager] = await getContractsFromArtifacts(hre, [
{
name: 'Lib_AddressManager',
signerOrProvider: deployer,
},
])
const proxyAdmin = await deploy({
hre,
name: 'ProxyAdmin',
args: [deployer],
postDeployAction: async (contract) => {
// Owner is temporarily set to the deployer.
await assertContractVariable(contract, 'owner', deployer)
},
})
let addressManagerOnProxy = await proxyAdmin.callStatic.addressManager()
if (addressManagerOnProxy !== addressManager.address) {
// Set the address manager on the proxy admin
console.log(
`ProxyAdmin(${proxyAdmin.address}).setAddressManager(${addressManager.address})`
)
const tx = await proxyAdmin.setAddressManager(addressManager.address)
await tx.wait()
}
// Validate the address manager was set correctly.
addressManagerOnProxy = await proxyAdmin.callStatic.addressManager()
assert(
addressManagerOnProxy === addressManager.address,
'AddressManager not set on ProxyAdmin'
)
}
deployFn.tags = ['ProxyAdmin', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
getDeploymentAddress,
deploy,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'Proxy__OVM_L1StandardBridge',
contract: 'L1ChugSplashProxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'getOwner', proxyAdmin)
},
})
}
deployFn.tags = ['L1StandardBridgeProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'L2OutputOracleProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['L2OutputOracleProxy', 'setup', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { deploy, getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [addressManager] = await getContractsFromArtifacts(hre, [
{
name: 'Lib_AddressManager',
signerOrProvider: deployer,
},
])
// The name in the address manager for this contract
const name = 'OVM_L1CrossDomainMessenger'
console.log(
`Setting up ResolvedDelegateProxy with AddressManager(${addressManager.address})`
)
const l1CrossDomainMessengerProxy = await deploy({
hre,
name: 'Proxy__OVM_L1CrossDomainMessenger',
contract: 'ResolvedDelegateProxy',
args: [addressManager.address, name],
})
let addr = await addressManager.getAddress(name)
if (addr !== l1CrossDomainMessengerProxy.address) {
console.log(
`AddressManager(${addressManager.address}).setAddress(${name}, ${l1CrossDomainMessengerProxy.address})`
)
const tx = await addressManager.setAddress(
name,
l1CrossDomainMessengerProxy.address
)
await tx.wait()
}
addr = await addressManager.getAddress(name)
assert(
addr === l1CrossDomainMessengerProxy.address,
`${name} not set correctly`
)
}
deployFn.tags = ['L1CrossDomainMessengerProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'OptimismPortalProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['OptimismPortalProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'OptimismMintableERC20FactoryProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['OptimismMintableERC20FactoryProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
getDeploymentAddress,
deploy,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'L1ERC721BridgeProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['L1ERC721BridgeProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getDeploymentAddress,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
await deploy({
hre,
name: 'SystemConfigProxy',
contract: 'Proxy',
args: [proxyAdmin],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'admin', proxyAdmin)
},
})
}
deployFn.tags = ['SystemConfigProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { deploy, getDeploymentAddress } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const proxyAdmin = await getDeploymentAddress(hre, 'ProxyAdmin')
// We only want to deploy the dgf on devnet for now
const network = await hre.ethers.provider.getNetwork()
const chainId = network.chainId
if (chainId === 900) {
console.log('Devnet detected, deploying DisputeGameFactoryProxy')
const disputeGameFactoryProxy = await deploy({
hre,
name: 'DisputeGameFactoryProxy',
contract: 'Proxy',
args: [proxyAdmin],
})
console.log(
`DisputeGameFactoryProxy deployed at ${disputeGameFactoryProxy.address}`
)
} else {
console.log('Skipping deployment of DisputeGameFactoryProxy')
}
}
deployFn.tags = ['DisputeGameFactoryProxy', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { predeploys } from '../src'
import {
assertContractVariable,
deploy,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
await deploy({
hre,
name: 'L1StandardBridge',
args: [L1CrossDomainMessengerProxy.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'MESSENGER',
L1CrossDomainMessengerProxy.address
)
await assertContractVariable(
contract,
'OTHER_BRIDGE',
predeploys.L2StandardBridge
)
},
})
}
deployFn.tags = ['L1StandardBridgeImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const OptimismPortalProxy = await getContractFromArtifact(
hre,
'OptimismPortalProxy'
)
await deploy({
hre,
name: 'L1CrossDomainMessenger',
args: [OptimismPortalProxy.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'PORTAL',
OptimismPortalProxy.address
)
},
})
}
deployFn.tags = ['L1CrossDomainMessengerImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import {
assertContractVariable,
deploy,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const isLiveDeployer =
deployer.toLowerCase() === hre.deployConfig.controller.toLowerCase()
const L2OutputOracleProxy = await getContractFromArtifact(
hre,
'L2OutputOracleProxy'
)
const Artifact__SystemConfigProxy = await hre.deployments.get(
'SystemConfigProxy'
)
const portalGuardian = hre.deployConfig.portalGuardian
const portalGuardianCode = await hre.ethers.provider.getCode(portalGuardian)
if (portalGuardianCode === '0x') {
console.log(
`WARNING: setting OptimismPortal.GUARDIAN to ${portalGuardian} and it has no code`
)
if (!isLiveDeployer) {
throw new Error(
'Do not deploy to production networks without the GUARDIAN being a contract'
)
}
}
// Deploy the OptimismPortal implementation as paused to
// ensure that users do not interact with it and instead
// interact with the proxied contract.
// The `portalGuardian` is set at the GUARDIAN.
await deploy({
hre,
name: 'OptimismPortal',
args: [
L2OutputOracleProxy.address,
portalGuardian,
true, // paused
Artifact__SystemConfigProxy.address,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'L2_ORACLE',
L2OutputOracleProxy.address
)
await assertContractVariable(
contract,
'GUARDIAN',
hre.deployConfig.portalGuardian
)
await assertContractVariable(
contract,
'SYSTEM_CONFIG',
Artifact__SystemConfigProxy.address
)
},
})
}
deployFn.tags = ['OptimismPortalImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
if (hre.deployConfig.l2BlockTime === 0) {
throw new Error(
'L2OutputOracle deployment: l2BlockTime must be greater than 0'
)
}
if (hre.deployConfig.l2OutputOracleSubmissionInterval === 0) {
throw new Error('L2OutputOracle deployment: submissionInterval cannot be 0')
}
await deploy({
hre,
name: 'L2OutputOracle',
args: [
hre.deployConfig.l2OutputOracleSubmissionInterval,
hre.deployConfig.l2BlockTime,
0,
0,
hre.deployConfig.l2OutputOracleProposer,
hre.deployConfig.l2OutputOracleChallenger,
hre.deployConfig.finalizationPeriodSeconds,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'SUBMISSION_INTERVAL',
hre.deployConfig.l2OutputOracleSubmissionInterval
)
await assertContractVariable(
contract,
'L2_BLOCK_TIME',
hre.deployConfig.l2BlockTime
)
await assertContractVariable(
contract,
'PROPOSER',
hre.deployConfig.l2OutputOracleProposer
)
await assertContractVariable(
contract,
'CHALLENGER',
hre.deployConfig.l2OutputOracleChallenger
)
await assertContractVariable(
contract,
'FINALIZATION_PERIOD_SECONDS',
hre.deployConfig.finalizationPeriodSeconds
)
},
})
}
deployFn.tags = ['L2OutputOracleImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { predeploys } from '../src'
import {
assertContractVariable,
deploy,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const L1CrossDomainMessengerProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1CrossDomainMessenger'
)
await deploy({
hre,
name: 'L1ERC721Bridge',
args: [L1CrossDomainMessengerProxy.address, predeploys.L2ERC721Bridge],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'MESSENGER',
L1CrossDomainMessengerProxy.address
)
},
})
}
deployFn.tags = ['L1ERC721BridgeImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import {
assertContractVariable,
deploy,
getContractFromArtifact,
} from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const L1StandardBridgeProxy = await getContractFromArtifact(
hre,
'Proxy__OVM_L1StandardBridge'
)
await deploy({
hre,
name: 'OptimismMintableERC20Factory',
args: [L1StandardBridgeProxy.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'BRIDGE',
L1StandardBridgeProxy.address
)
},
})
}
deployFn.tags = ['OptimismMintableERC20FactoryImpl', 'setup', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
// We only want to deploy the dgf on devnet for now
const network = await hre.ethers.provider.getNetwork()
const chainId = network.chainId
if (chainId === 900) {
const disputeGameFactory = await deploy({
hre,
name: 'DisputeGameFactory',
args: [],
})
console.log(`DisputeGameFactory deployed at ${disputeGameFactory.address}`)
} else {
console.log('Skipping deployment of DisputeGameFactory implementation')
}
}
deployFn.tags = ['DisputeGameFactoryImpl', 'setup', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import { BigNumber } from 'ethers'
import { defaultResourceConfig } from '../src/constants'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const batcherHash = hre.ethers.utils
.hexZeroPad(hre.deployConfig.batchSenderAddress, 32)
.toLowerCase()
const l2GenesisBlockGasLimit = BigNumber.from(
hre.deployConfig.l2GenesisBlockGasLimit
)
const l2GasLimitLowerBound = BigNumber.from(
defaultResourceConfig.systemTxMaxGas +
defaultResourceConfig.maxResourceLimit
)
if (l2GenesisBlockGasLimit.lt(l2GasLimitLowerBound)) {
throw new Error(
`L2 genesis block gas limit must be at least ${l2GasLimitLowerBound}`
)
}
await deploy({
hre,
name: 'SystemConfig',
args: [
hre.deployConfig.finalSystemOwner,
hre.deployConfig.gasPriceOracleOverhead,
hre.deployConfig.gasPriceOracleScalar,
batcherHash,
l2GenesisBlockGasLimit,
hre.deployConfig.p2pSequencerAddress,
defaultResourceConfig,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'owner',
hre.deployConfig.finalSystemOwner
)
await assertContractVariable(
contract,
'overhead',
hre.deployConfig.gasPriceOracleOverhead
)
await assertContractVariable(
contract,
'scalar',
hre.deployConfig.gasPriceOracleScalar
)
await assertContractVariable(contract, 'batcherHash', batcherHash)
await assertContractVariable(
contract,
'unsafeBlockSigner',
hre.deployConfig.p2pSequencerAddress
)
const config = await contract.resourceConfig()
assert(config.maxResourceLimit === defaultResourceConfig.maxResourceLimit)
assert(
config.elasticityMultiplier ===
defaultResourceConfig.elasticityMultiplier
)
assert(
config.baseFeeMaxChangeDenominator ===
defaultResourceConfig.baseFeeMaxChangeDenominator
)
assert(
BigNumber.from(config.systemTxMaxGas).eq(
defaultResourceConfig.systemTxMaxGas
)
)
assert(
BigNumber.from(config.minimumBaseFee).eq(
defaultResourceConfig.minimumBaseFee
)
)
assert(
BigNumber.from(config.maximumBaseFee).eq(
defaultResourceConfig.maximumBaseFee
)
)
},
})
}
deployFn.tags = ['SystemConfigImpl', 'setup', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, addressManager] = await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'Lib_AddressManager',
signerOrProvider: deployer,
},
])
let addressManagerOwner = await addressManager.callStatic.owner()
if (addressManagerOwner !== proxyAdmin.address) {
console.log(
`AddressManager(${addressManager.address}).transferOwnership(${proxyAdmin.address})`
)
const tx = await addressManager.transferOwnership(proxyAdmin.address)
await tx.wait()
}
addressManagerOwner = await addressManager.callStatic.owner()
assert(
addressManagerOwner === proxyAdmin.address,
'AddressManager owner not set correctly'
)
}
deployFn.tags = ['AddressManager', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
// We only want to deploy the dgf on devnet for now
const network = await hre.ethers.provider.getNetwork()
const chainId = network.chainId
// The DisputeGameFactory is only deployed on devnet
if (chainId === 900) {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, disputeGameFactoryProxy, disputeGameFactoryImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'DisputeGameFactoryProxy',
iface: 'DisputeGameFactory',
signerOrProvider: deployer,
},
{
name: 'DisputeGameFactory',
},
])
const finalOwner = hre.deployConfig.finalSystemOwner
try {
const tx = await proxyAdmin.upgradeAndCall(
disputeGameFactoryProxy.address,
disputeGameFactoryImpl.address,
disputeGameFactoryProxy.interface.encodeFunctionData('initialize', [
finalOwner,
])
)
await tx.wait()
} catch (e) {
console.log('DisputeGameFactory already initialized')
}
const fetchedOwner = await disputeGameFactoryProxy.callStatic.owner()
assert(fetchedOwner === finalOwner)
console.log('Updgraded and initialized DisputeGameFactory')
} else {
console.log('Skipping initialization of DisputeGameFactory')
}
}
deployFn.tags = ['DisputeGameFactoryInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { BigNumber } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { defaultResourceConfig } from '../src/constants'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, systemConfigProxy, systemConfigImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'SystemConfigProxy',
iface: 'SystemConfig',
signerOrProvider: deployer,
},
{
name: 'SystemConfig',
},
])
const batcherHash = hre.ethers.utils
.hexZeroPad(hre.deployConfig.batchSenderAddress, 32)
.toLowerCase()
const l2GenesisBlockGasLimit = BigNumber.from(
hre.deployConfig.l2GenesisBlockGasLimit
)
const l2GasLimitLowerBound = BigNumber.from(
defaultResourceConfig.systemTxMaxGas +
defaultResourceConfig.maxResourceLimit
)
if (l2GenesisBlockGasLimit.lt(l2GasLimitLowerBound)) {
throw new Error(
`L2 genesis block gas limit must be at least ${l2GasLimitLowerBound}`
)
}
try {
const tx = await proxyAdmin.upgradeAndCall(
systemConfigProxy.address,
systemConfigImpl.address,
systemConfigImpl.interface.encodeFunctionData('initialize', [
hre.deployConfig.finalSystemOwner,
hre.deployConfig.gasPriceOracleOverhead,
hre.deployConfig.gasPriceOracleScalar,
batcherHash,
l2GenesisBlockGasLimit,
hre.deployConfig.p2pSequencerAddress,
defaultResourceConfig,
])
)
await tx.wait()
} catch (e) {
console.log('SystemConfig already initialized')
console.log(e)
}
const version = await systemConfigProxy.callStatic.version()
console.log(`SystemConfig version: ${version}`)
console.log('Upgraded SystemConfig')
}
deployFn.tags = ['SystemConfigInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, l1StandardBridgeProxy, l1StandardBridgeImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'Proxy__OVM_L1StandardBridge',
iface: 'L1StandardBridge',
signerOrProvider: deployer,
},
{
name: 'L1StandardBridge',
},
])
const proxyType = await proxyAdmin.callStatic.proxyType(
l1StandardBridgeProxy.address
)
if (proxyType !== 1) {
console.log(
`ProxyAdmin(${proxyAdmin.address}).setProxyType(${l1StandardBridgeProxy.address}, 1)`
)
// Set the L1StandardBridge to the UPGRADEABLE proxy type.
const tx = await proxyAdmin.setProxyType(l1StandardBridgeProxy.address, 1)
await tx.wait()
}
try {
const tx = await proxyAdmin.upgrade(
l1StandardBridgeProxy.address,
l1StandardBridgeImpl.address
)
await tx.wait()
} catch (e) {
console.log('L1StandardBridge already initialized')
}
const version = await l1StandardBridgeProxy.callStatic.version()
console.log(`L1StandardBridge version: ${version}`)
console.log('Upgraded L1StandardBridge')
}
deployFn.tags = ['L1StandardBridgeInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, l1ERC721BridgeProxy, l1ERC721BridgeImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'L1ERC721BridgeProxy',
iface: 'L1ERC721Bridge',
signerOrProvider: deployer,
},
{
name: 'L1ERC721Bridge',
},
])
try {
const tx = await proxyAdmin.upgrade(
l1ERC721BridgeProxy.address,
l1ERC721BridgeImpl.address
)
await tx.wait()
} catch (e) {
console.log('L1ERC721Bridge already initialized')
}
const version = await l1ERC721BridgeProxy.callStatic.version()
console.log(`L1ERC721Bridge version: ${version}`)
console.log('Upgraded L1ERC721Bridge')
}
deployFn.tags = ['L1ERC721BridgeInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, mintableERC20FactoryProxy, mintableERC20FactoryImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'OptimismMintableERC20FactoryProxy',
iface: 'OptimismMintableERC20Factory',
signerOrProvider: deployer,
},
{
name: 'OptimismMintableERC20Factory',
},
])
try {
const tx = await proxyAdmin.upgrade(
mintableERC20FactoryProxy.address,
mintableERC20FactoryImpl.address
)
await tx.wait()
} catch (e) {
console.log('OptimismMintableERC20Factory already initialized')
}
const version = await mintableERC20FactoryProxy.callStatic.version()
console.log(`OptimismMintableERC20Factory version: ${version}`)
console.log('Upgraded OptimismMintableERC20Factory')
}
deployFn.tags = ['OptimismMintableERC20FactoryInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, l1CrossDomainMessengerProxy, l1CrossDomainMessengerImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'Proxy__OVM_L1CrossDomainMessenger',
iface: 'L1CrossDomainMessenger',
signerOrProvider: deployer,
},
{
name: 'L1CrossDomainMessenger',
},
])
const proxyType = await proxyAdmin.callStatic.proxyType(
l1CrossDomainMessengerProxy.address
)
if (proxyType !== 2) {
console.log(
`ProxyAdmin(${proxyAdmin.address}).setProxyType(${l1CrossDomainMessengerProxy.address}, 2)`
)
// Set the L1CrossDomainMessenger to the RESOLVED proxy type.
const tx = await proxyAdmin.setProxyType(
l1CrossDomainMessengerProxy.address,
2
)
await tx.wait()
}
const name = 'OVM_L1CrossDomainMessenger'
const implementationName = proxyAdmin.implementationName(
l1CrossDomainMessengerImpl.address
)
if (implementationName !== name) {
console.log(
`ProxyAdmin(${proxyAdmin.address}).setImplementationName(${l1CrossDomainMessengerImpl.address}, 'OVM_L1CrossDomainMessenger')`
)
const tx = await proxyAdmin.setImplementationName(
l1CrossDomainMessengerProxy.address,
name
)
await tx.wait()
}
try {
const tx = await proxyAdmin.upgradeAndCall(
l1CrossDomainMessengerProxy.address,
l1CrossDomainMessengerImpl.address,
l1CrossDomainMessengerImpl.interface.encodeFunctionData('initialize')
)
await tx.wait()
} catch (e) {
console.log('L1CrossDomainMessenger already initialized')
}
const version = await l1CrossDomainMessengerProxy.callStatic.version()
console.log(`L1CrossDomainMessenger version: ${version}`)
console.log('Upgraded L1CrossDomainMessenger')
}
deployFn.tags = ['L1CrossDomainMessengerInitialize', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, l2OutputOracleProxy, l2OutputOracleImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'L2OutputOracleProxy',
iface: 'L2OutputOracle',
signerOrProvider: deployer,
},
{
name: 'L2OutputOracle',
},
])
const startingBlockNumber = hre.deployConfig.l2OutputOracleStartingBlockNumber
let startingTimestamp = hre.deployConfig.l2OutputOracleStartingTimestamp
if (startingTimestamp < 0) {
const l1StartingBlock = await hre.ethers.provider.getBlock(
hre.deployConfig.l1StartingBlockTag
)
if (l1StartingBlock === null) {
throw new Error(
`Cannot fetch block tag ${hre.deployConfig.l1StartingBlockTag}`
)
}
startingTimestamp = l1StartingBlock.timestamp
}
try {
const tx = await proxyAdmin.upgradeAndCall(
l2OutputOracleProxy.address,
l2OutputOracleImpl.address,
l2OutputOracleProxy.interface.encodeFunctionData('initialize', [
startingBlockNumber,
startingTimestamp,
])
)
await tx.wait()
} catch (e) {
console.log('L2OutputOracle already initialized')
}
const fetchedStartingBlockNumber =
await l2OutputOracleProxy.callStatic.startingBlockNumber()
const fetchedStartingTimestamp =
await l2OutputOracleProxy.callStatic.startingTimestamp()
assert(fetchedStartingBlockNumber.toNumber() === startingBlockNumber)
assert(fetchedStartingTimestamp.toNumber() === startingTimestamp)
console.log('Updgraded and initialized L2OutputOracle')
const version = await l2OutputOracleProxy.callStatic.version()
console.log(`L2OutputOracle version: ${version}`)
}
deployFn.tags = ['L2OutputOracleInitialize', 'l1']
export default deployFn
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin, optimismPortalProxy, optimismPortalImpl] =
await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
{
name: 'OptimismPortalProxy',
iface: 'OptimismPortal',
signerOrProvider: deployer,
},
{
name: 'OptimismPortal',
},
])
// Initialize the portal, setting paused to false
try {
const tx = await proxyAdmin.upgradeAndCall(
optimismPortalProxy.address,
optimismPortalImpl.address,
optimismPortalProxy.interface.encodeFunctionData('initialize', [false])
)
await tx.wait()
} catch (e) {
console.log('OptimismPortal already initialized')
}
const isPaused = await optimismPortalProxy.callStatic.paused()
assert(isPaused === false)
console.log('Upgraded and initialized OptimismPortal')
const version = await optimismPortalProxy.callStatic.version()
console.log(`OptimismPortal version: ${version}`)
}
deployFn.tags = ['OptimismPortalInitialize', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { awaitCondition } from '@eth-optimism/core-utils'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import { getContractsFromArtifacts } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const [proxyAdmin] = await getContractsFromArtifacts(hre, [
{
name: 'ProxyAdmin',
signerOrProvider: deployer,
},
])
const finalOwner = hre.deployConfig.finalSystemOwner
const proxyAdminOwner = await proxyAdmin.callStatic.owner()
if (proxyAdminOwner !== finalOwner) {
const tx = await proxyAdmin.transferOwnership(finalOwner)
await tx.wait()
await awaitCondition(
async () => {
return (await proxyAdmin.callStatic.owner()) === finalOwner
},
30000,
1000
)
}
}
deployFn.tags = ['ProxyAdmin', 'transferOwnership', 'l1']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
await deploy({
hre,
name: 'L1Block',
args: [],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'DEPOSITOR_ACCOUNT',
ethers.utils.getAddress('0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001')
)
},
})
}
deployFn.tags = ['L1BlockImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const Artifact__L1CrossDomainMessenger = await hre.companionNetworks[
'l1'
].deployments.get('L1CrossDomainMessengerProxy')
await deploy({
hre,
name: 'L2CrossDomainMessenger',
args: [Artifact__L1CrossDomainMessenger.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'OTHER_MESSENGER',
ethers.utils.getAddress(Artifact__L1CrossDomainMessenger.address)
)
},
})
}
deployFn.tags = ['L2CrossDomainMessengerImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const Artifact__L1StandardBridge = await hre.companionNetworks[
'l1'
].deployments.get('L1StandardBridgeProxy')
await deploy({
hre,
name: 'L2StandardBridge',
args: [Artifact__L1StandardBridge.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'OTHER_BRIDGE',
ethers.utils.getAddress(Artifact__L1StandardBridge.address)
)
},
})
}
deployFn.tags = ['L2StandardBridgeImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
await deploy({
hre,
name: 'L2ToL1MessagePasser',
args: [],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'MESSAGE_VERSION', 1)
},
})
}
deployFn.tags = ['L2ToL1MessagePasserImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { ethers } from 'ethers'
import { predeploys } from '../src/constants'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const Artifact__L1ERC721Bridge = await hre.companionNetworks[
'l1'
].deployments.get('L1ERC721BridgeProxy')
await deploy({
hre,
name: 'L2ERC721Bridge',
args: [predeploys.L2CrossDomainMessenger, Artifact__L1ERC721Bridge.address],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'MESSENGER',
ethers.utils.getAddress(predeploys.L2CrossDomainMessenger)
)
await assertContractVariable(
contract,
'OTHER_BRIDGE',
ethers.utils.getAddress(Artifact__L1ERC721Bridge.address)
)
},
})
}
deployFn.tags = ['L2ERC721BridgeImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
await deploy({
hre,
name: 'GasPriceOracle',
args: [],
postDeployAction: async (contract) => {
await assertContractVariable(contract, 'DECIMALS', 6)
},
})
}
deployFn.tags = ['GasPriceOracle', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { ethers } from 'ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const l1 = hre.network.companionNetworks['l1']
const deployConfig = hre.getDeployConfig(l1)
const sequencerFeeVaultRecipient = deployConfig.sequencerFeeVaultRecipient
if (sequencerFeeVaultRecipient === ethers.constants.AddressZero) {
throw new Error(`SequencerFeeVault RECIPIENT undefined`)
}
const sequencerFeeVaultMinimumWithdrawalAmount =
deployConfig.sequencerFeeVaultMinimumWithdrawalAmount
const sequencerFeeVaultWithdrawalNetwork =
deployConfig.sequencerFeeVaultWithdrawalNetwork
if (sequencerFeeVaultWithdrawalNetwork >= 2) {
throw new Error('SequencerFeeVault WITHDRAWAL_NETWORK must be 0 or 1')
}
await deploy({
hre,
name: 'SequencerFeeVault',
args: [
sequencerFeeVaultRecipient,
sequencerFeeVaultMinimumWithdrawalAmount,
sequencerFeeVaultWithdrawalNetwork,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'RECIPIENT',
ethers.utils.getAddress(sequencerFeeVaultRecipient)
)
await assertContractVariable(
contract,
'MIN_WITHDRAWAL_AMOUNT',
sequencerFeeVaultMinimumWithdrawalAmount
)
await assertContractVariable(
contract,
'WITHDRAWAL_NETWORK',
sequencerFeeVaultWithdrawalNetwork
)
},
})
}
deployFn.tags = ['SequencerFeeVaultImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { ethers } from 'ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const l1 = hre.network.companionNetworks['l1']
const deployConfig = hre.getDeployConfig(l1)
const baseFeeVaultRecipient = deployConfig.baseFeeVaultRecipient
if (baseFeeVaultRecipient === ethers.constants.AddressZero) {
throw new Error('BaseFeeVault RECIPIENT undefined')
}
const baseFeeVaultMinimumWithdrawalAmount =
deployConfig.baseFeeVaultMinimumWithdrawalAmount
const baseFeeVaultWithdrawalNetwork =
deployConfig.baseFeeVaultWithdrawalNetwork
if (baseFeeVaultWithdrawalNetwork >= 2) {
throw new Error('BaseFeeVault WITHDRAWAL_NETWORK must be 0 or 1')
}
await deploy({
hre,
name: 'BaseFeeVault',
args: [
baseFeeVaultRecipient,
baseFeeVaultMinimumWithdrawalAmount,
baseFeeVaultWithdrawalNetwork,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'RECIPIENT',
ethers.utils.getAddress(baseFeeVaultRecipient)
)
await assertContractVariable(
contract,
'MIN_WITHDRAWAL_AMOUNT',
baseFeeVaultMinimumWithdrawalAmount
)
await assertContractVariable(
contract,
'WITHDRAWAL_NETWORK',
baseFeeVaultWithdrawalNetwork
)
},
})
}
deployFn.tags = ['BaseFeeVaultImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { ethers } from 'ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
const deployFn: DeployFunction = async (hre) => {
const l1 = hre.network.companionNetworks['l1']
const deployConfig = hre.getDeployConfig(l1)
const l1FeeVaultRecipient = deployConfig.l1FeeVaultRecipient
if (l1FeeVaultRecipient === ethers.constants.AddressZero) {
throw new Error('L1FeeVault RECIPIENT undefined')
}
const l1FeeVaultMinimumWithdrawalAmount =
deployConfig.l1FeeVaultMinimumWithdrawalAmount
const l1FeeVaultWithdrawalNetwork = deployConfig.l1FeeVaultWithdrawalNetwork
if (l1FeeVaultWithdrawalNetwork >= 2) {
throw new Error('L1FeeVault WITHDRAWAL_NETWORK must be 0 or 1')
}
await deploy({
hre,
name: 'L1FeeVault',
args: [
l1FeeVaultRecipient,
l1FeeVaultMinimumWithdrawalAmount,
l1FeeVaultWithdrawalNetwork,
],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'RECIPIENT',
ethers.utils.getAddress(l1FeeVaultRecipient)
)
await assertContractVariable(
contract,
'MIN_WITHDRAWAL_AMOUNT',
l1FeeVaultMinimumWithdrawalAmount
)
await assertContractVariable(
contract,
'WITHDRAWAL_NETWORK',
l1FeeVaultWithdrawalNetwork
)
},
})
}
deployFn.tags = ['L1FeeVaultImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
import { predeploys } from '../src/constants'
const deployFn: DeployFunction = async (hre) => {
await deploy({
hre,
name: 'OptimismMintableERC20Factory',
args: [predeploys.L2StandardBridge],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'BRIDGE',
ethers.utils.getAddress(predeploys.L2StandardBridge)
)
},
})
}
deployFn.tags = ['OptimismMintableERC20FactoryImpl', 'l2']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'ethers'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import { assertContractVariable, deploy } from '../src/deploy-utils'
import { predeploys } from '../src/constants'
const deployFn: DeployFunction = async (hre) => {
const OptimismMintableERC721Factory = await hre.ethers.getContractAt(
'OptimismMintableERC721Factory',
predeploys.OptimismMintableERC721Factory
)
const remoteChainId = await OptimismMintableERC721Factory.REMOTE_CHAIN_ID()
await deploy({
hre,
name: 'OptimismMintableERC721Factory',
args: [predeploys.L2StandardBridge, remoteChainId],
postDeployAction: async (contract) => {
await assertContractVariable(
contract,
'BRIDGE',
ethers.utils.getAddress(predeploys.L2StandardBridge)
)
await assertContractVariable(contract, 'REMOTE_CHAIN_ID', remoteChainId)
},
})
}
deployFn.tags = ['OptimismMintableERC721FactoryImpl', 'l2']
export default deployFn
import assert from 'assert'
import { URLSearchParams } from 'url'
import { ethers, Contract } from 'ethers'
import { Provider } from '@ethersproject/abstract-provider'
import { Signer } from '@ethersproject/abstract-signer'
import { sleep } from '@eth-optimism/core-utils'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { Deployment, DeployResult } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
/**
* Wrapper around hardhat-deploy with some extra features.
*
* @param opts Options for the deployment.
* @param opts.hre HardhatRuntimeEnvironment.
* @param opts.contract Name of the contract to deploy.
* @param opts.name Name to use for the deployment file.
* @param opts.iface Interface to use for the returned contract.
* @param opts.args Arguments to pass to the contract constructor.
* @param opts.postDeployAction Action to perform after the contract is deployed.
* @returns Deployed contract object.
*/
export const deploy = async ({
hre,
name,
iface,
args,
contract,
postDeployAction,
}: {
hre: HardhatRuntimeEnvironment
name: string
args: any[]
contract?: string
iface?: string
postDeployAction?: (contract: Contract) => Promise<void>
}): Promise<Contract> => {
const { deployer } = await hre.getNamedAccounts()
// Hardhat deploy will usually do this check for us, but currently doesn't also consider
// external deployments when doing this check. By doing the check ourselves, we also get to
// consider external deployments. If we already have the deployment, return early.
let result: Deployment | DeployResult = await hre.deployments.getOrNull(name)
// Wrap in a try/catch in case there is not a deployConfig for the current network.
let numDeployConfirmations: number
try {
numDeployConfirmations = hre.deployConfig.numDeployConfirmations
} catch (e) {
numDeployConfirmations = 1
}
if (result) {
console.log(`skipping ${name}, using existing at ${result.address}`)
} else {
result = await hre.deployments.deploy(name, {
contract,
from: deployer,
args,
log: true,
waitConfirmations: numDeployConfirmations,
})
console.log(`Deployed ${name} at ${result.address}`)
// Only wait for the transaction if it was recently deployed in case the
// result was deployed a long time ago and was pruned from the backend.
await hre.ethers.provider.waitForTransaction(result.transactionHash)
}
// Check to make sure there is code
const code = await hre.ethers.provider.getCode(result.address)
if (code === '0x') {
throw new Error(`no code for ${result.address}`)
}
// Create the contract object to return.
const created = asAdvancedContract({
confirmations: numDeployConfirmations,
contract: new Contract(
result.address,
iface !== undefined
? (await hre.ethers.getContractFactory(iface)).interface
: result.abi,
hre.ethers.provider.getSigner(deployer)
),
})
// Run post-deploy actions if necessary.
if ((result as DeployResult).newlyDeployed) {
if (postDeployAction) {
await postDeployAction(created)
}
}
return created
}
/**
* Returns a version of the contract object which modifies all of the input contract's methods to
* automatically await transaction receipts and confirmations. Will also throw if we timeout while
* waiting for a transaction to be included in a block.
*
* @param opts Options for the contract.
* @param opts.hre HardhatRuntimeEnvironment.
* @param opts.contract Contract to wrap.
* @returns Wrapped contract object.
*/
export const asAdvancedContract = (opts: {
contract: Contract
confirmations?: number
gasPrice?: number
}): Contract => {
// Temporarily override Object.defineProperty to bypass ether's object protection.
const def = Object.defineProperty
Object.defineProperty = (obj, propName, prop) => {
prop.writable = true
return def(obj, propName, prop)
}
const contract = new Contract(
opts.contract.address,
opts.contract.interface,
opts.contract.signer || opts.contract.provider
)
// Now reset Object.defineProperty
Object.defineProperty = def
for (const fnName of Object.keys(contract.functions)) {
const fn = contract[fnName].bind(contract)
;(contract as any)[fnName] = async (...args: any) => {
// We want to use the configured gas price but we need to set the gas price to zero if we're
// triggering a static function.
let gasPrice = opts.gasPrice
if (contract.interface.getFunction(fnName).constant) {
gasPrice = 0
}
// Now actually trigger the transaction (or call).
const tx = await fn(...args, {
gasPrice,
})
// Meant for static calls, we don't need to wait for anything, we get the result right away.
if (typeof tx !== 'object' || typeof tx.wait !== 'function') {
return tx
}
// Wait for the transaction to be included in a block and wait for the specified number of
// deployment confirmations.
const maxTimeout = 120
let timeout = 0
while (true) {
await sleep(1000)
const receipt = await contract.provider.getTransactionReceipt(tx.hash)
if (receipt === null) {
timeout++
if (timeout > maxTimeout) {
throw new Error('timeout exceeded waiting for txn to be mined')
}
} else if (receipt.confirmations >= (opts.confirmations || 0)) {
return tx
}
}
}
}
return contract
}
/**
* Creates a contract object from a deployed artifact.
*
* @param hre HardhatRuntimeEnvironment.
* @param name Name of the deployed contract to get an object for.
* @param opts Options for the contract.
* @param opts.iface Optional interface to use for the contract object.
* @param opts.signerOrProvider Optional signer or provider to use for the contract object.
* @returns Contract object.
*/
export const getContractFromArtifact = async (
hre: HardhatRuntimeEnvironment,
name: string,
opts: {
iface?: string
signerOrProvider?: Signer | Provider | string
} = {}
): Promise<ethers.Contract> => {
const artifact = await hre.deployments.get(name)
// Get the deployed contract's interface.
let iface = new hre.ethers.utils.Interface(artifact.abi)
// Override with optional iface name if requested.
if (opts.iface) {
const factory = await hre.ethers.getContractFactory(opts.iface)
iface = factory.interface
}
let signerOrProvider: Signer | Provider = hre.ethers.provider
if (opts.signerOrProvider) {
if (typeof opts.signerOrProvider === 'string') {
signerOrProvider = hre.ethers.provider.getSigner(opts.signerOrProvider)
} else {
signerOrProvider = opts.signerOrProvider
}
}
let numDeployConfirmations: number
try {
numDeployConfirmations = hre.deployConfig.numDeployConfirmations
} catch (e) {
numDeployConfirmations = 1
}
return asAdvancedContract({
confirmations: numDeployConfirmations,
contract: new hre.ethers.Contract(
artifact.address,
iface,
signerOrProvider
),
})
}
/**
* Gets multiple contract objects from their respective deployed artifacts.
*
* @param hre HardhatRuntimeEnvironment.
* @param configs Array of contract names and options.
* @returns Array of contract objects.
*/
export const getContractsFromArtifacts = async (
hre: HardhatRuntimeEnvironment,
configs: Array<{
name: string
iface?: string
signerOrProvider?: Signer | Provider | string
}>
): Promise<ethers.Contract[]> => {
const contracts = []
for (const config of configs) {
contracts.push(await getContractFromArtifact(hre, config.name, config))
}
return contracts
}
/**
* Helper function for asserting that a contract variable is set to the expected value.
*
* @param contract Contract object to query.
* @param variable Name of the variable to query.
* @param expected Expected value of the variable.
*/
export const assertContractVariable = async (
contract: ethers.Contract,
variable: string,
expected: any
) => {
// Need to make a copy that doesn't have a signer or we get the error that contracts with
// signers cannot override the from address.
const temp = new ethers.Contract(
contract.address,
contract.interface,
contract.provider
)
const actual = await temp.callStatic[variable]({
from: ethers.constants.AddressZero,
})
if (ethers.utils.isAddress(expected)) {
assert(
actual.toLowerCase() === expected.toLowerCase(),
`[FATAL] ${variable} is ${actual} but should be ${expected}`
)
return
}
assert(
actual === expected || (actual.eq && actual.eq(expected)),
`[FATAL] ${variable} is ${actual} but should be ${expected}`
)
}
/**
* Returns the address for a given deployed contract by name.
*
* @param hre HardhatRuntimeEnvironment.
* @param name Name of the deployed contract.
* @returns Address of the deployed contract.
*/
export const getDeploymentAddress = async (
hre: HardhatRuntimeEnvironment,
name: string
): Promise<string> => {
const deployment = await hre.deployments.get(name)
return deployment.address
}
/**
* JSON-ifies an ethers transaction object.
*
* @param tx Ethers transaction object.
* @returns JSON-ified transaction object.
*/
export const printJsonTransaction = (tx: ethers.PopulatedTransaction): void => {
console.log(
'JSON transaction parameters:\n' +
JSON.stringify(
{
from: tx.from,
to: tx.to,
data: tx.data,
value: tx.value,
chainId: tx.chainId,
},
null,
2
)
)
}
/**
* Helper for transferring a Proxy to a target contract.
*
* @param opts Options for executing the step.
* @param opts.isLiveDeployer True if the deployer is live.
* @param opts.proxy proxy contract.
* @param opts.target target contract.
*/
export const doOwnershipTransfer = async (opts: {
isLiveDeployer?: boolean
proxy: ethers.Contract
name: string
transferFunc: string
target: ethers.Contract
}): Promise<void> => {
if (opts.isLiveDeployer) {
console.log(`Setting ${opts.name} owner to target ${opts.target.address}`)
await opts.proxy[opts.transferFunc](opts.target.address)
} else {
const tx = await opts.proxy.populateTransaction[opts.transferFunc](
opts.target.address
)
console.log(`
Please transfer ${opts.name} (proxy) owner to MSD
- ${opts.name} address: ${opts.proxy.address}
- target address: ${opts.target.address}
`)
printJsonTransaction(tx)
printCastCommand(tx)
await printTenderlySimulationLink(opts.target.provider, tx)
}
}
/**
* Check if the script should submit the transaction or wait for the deployer to do it manually.
*
* @param hre HardhatRuntimeEnvironment.
* @param ovveride Allow manually disabling live transaction submission. Useful for testing.
* @returns True if the current step is the target step.
*/
export const liveDeployer = async (opts: {
hre: HardhatRuntimeEnvironment
disabled: string | undefined
}): Promise<boolean> => {
if (!!opts.disabled) {
console.log('Live deployer manually disabled')
return false
}
const { deployer } = await opts.hre.getNamedAccounts()
const ret =
deployer.toLowerCase() === opts.hre.deployConfig.controller.toLowerCase()
console.log('Setting live deployer to', ret)
return ret
}
/**
* Prints a direct link to a Tenderly simulation.
*
* @param provider Ethers Provider.
* @param tx Ethers transaction object.
*/
export const printTenderlySimulationLink = async (
provider: ethers.providers.Provider,
tx: ethers.PopulatedTransaction
): Promise<void> => {
if (process.env.TENDERLY_PROJECT && process.env.TENDERLY_USERNAME) {
console.log(
`https://dashboard.tenderly.co/${process.env.TENDERLY_PROJECT}/${
process.env.TENDERLY_USERNAME
}/simulator/new?${new URLSearchParams({
network: (await provider.getNetwork()).chainId.toString(),
contractAddress: tx.to,
rawFunctionInput: tx.data,
from: tx.from,
}).toString()}`
)
}
}
/**
* Prints a cast commmand for submitting a given transaction.
*
* @param tx Ethers transaction object.
*/
export const printCastCommand = (tx: ethers.PopulatedTransaction): void => {
if (process.env.CAST_COMMANDS) {
if (!!tx.value && tx.value.gt(0)) {
console.log(
`cast send ${tx.to} ${tx.data} --from ${tx.from} --value ${tx.value}`
)
} else {
console.log(`cast send ${tx.to} ${tx.data} --from ${tx.from} `)
}
}
}
import { task } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'
task('accounts', 'Prints the list of accounts', async (_, hre) => {
const accounts = await hre.ethers.getSigners()
for (const account of accounts) {
console.log(account.address)
}
})
import { spawn as spawn } from 'child_process'
import { task, types } from 'hardhat/config'
import * as foundryup from '@foundry-rs/easy-foundryup'
import 'hardhat-deploy'
import { ethers } from 'ethers'
interface ForgeVerifyArgs {
chainId: string
compilerVersion: string
constructorArgs: string
optimizerRuns: number
contractAddress: string
contractName: string
etherscanApiKey: string
}
const verifyArgs = (opts: ForgeVerifyArgs): string[] => {
const allArgs: string[] = []
if (!opts.chainId) {
throw new Error(`No chain-id provided`)
}
allArgs.push(`--chain`, opts.chainId)
if (opts.compilerVersion) {
allArgs.push('--compiler-version', opts.compilerVersion)
}
if (opts.constructorArgs) {
allArgs.push('--constructor-args', opts.constructorArgs)
}
if (typeof opts.optimizerRuns === 'number') {
allArgs.push('--num-of-optimizations', opts.optimizerRuns.toString())
}
allArgs.push('--watch')
if (!opts.contractAddress) {
throw new Error('No contract address provided')
}
allArgs.push(opts.contractAddress)
if (!opts.contractName) {
throw new Error('No contract name provided')
}
allArgs.push(opts.contractName)
if (!opts.etherscanApiKey) {
throw new Error('No Etherscan API key provided')
}
allArgs.push(opts.etherscanApiKey)
return allArgs
}
const spawnVerify = async (opts: ForgeVerifyArgs): Promise<boolean> => {
const args = ['verify-contract', ...verifyArgs(opts)]
const forgeCmd = await foundryup.getForgeCommand()
return new Promise((resolve) => {
const process = spawn(forgeCmd, args, {
stdio: 'inherit',
})
process.on('exit', (code) => {
resolve(code === 0)
})
})
}
task('forge-contract-verify', 'Verify contracts using forge')
.addOptionalParam(
'contract',
'Name of the contract to verify',
'',
types.string
)
.addOptionalParam(
'etherscanApiKey',
'Etherscan API key',
process.env.ETHERSCAN_API_KEY,
types.string
)
.setAction(async (args, hre) => {
const deployments = await hre.deployments.all()
if (args.contract !== '') {
if (!deployments[args.contract]) {
throw new Error(
`Contract ${args.contract} not found in ${hre.network} deployments`
)
}
}
for (const [contract, deployment] of Object.entries(deployments)) {
if (args.contract !== '' && args.contract !== contract) {
continue
}
const chainId = await hre.getChainId()
const contractAddress = deployment.address
const etherscanApiKey = args.etherscanApiKey
let metadata = deployment.metadata as any
// Handle double nested JSON stringify
while (typeof metadata === 'string') {
metadata = JSON.parse(metadata) as any
}
const contractName = Object.values(
metadata.settings.compilationTarget
)[0].toString()
const compilerVersion = metadata.compiler.version
const iface = new ethers.utils.Interface(deployment.abi)
const constructorArgs = iface.encodeDeploy(deployment.args)
const optimizerRuns = metadata.settings.optimizer
const success = await spawnVerify({
chainId,
compilerVersion,
constructorArgs,
optimizerRuns,
contractAddress,
contractName,
etherscanApiKey,
})
if (success) {
console.log(`Contract verification successful for ${contractName}`)
} else {
console.log(`Contract verification unsuccesful for ${contractName}`)
}
}
})
import './deposits'
import './rekey'
import './check-op-node'
import './watch'
import './forge-verify'
import './validate-spacers'
import './solidity'
import './accounts'
import './check-l2'
import './update-dynamic-oracle-config'
import './generate-deploy-config'
import { task } from 'hardhat/config'
import { hdkey } from 'ethereumjs-wallet'
import * as bip39 from 'bip39'
task('rekey', 'Generates a new set of keys for a test network').setAction(
async () => {
const mnemonic = bip39.generateMnemonic()
const pathPrefix = "m/44'/60'/0'/0"
const labels = ['Admin', 'Proposer', 'Batcher', 'Sequencer']
const hdwallet = hdkey.fromMasterSeed(await bip39.mnemonicToSeed(mnemonic))
console.log(`Mnemonic: ${mnemonic}`)
for (let i = 0; i < labels.length; i++) {
const label = labels[i]
const wallet = hdwallet.derivePath(`${pathPrefix}/${i}`).getWallet()
const addr = '0x' + wallet.getAddress().toString('hex')
const pk = wallet.getPrivateKey().toString('hex')
console.log()
console.log(`${label}: ${addr}`)
console.log(`Private Key: ${pk}`)
}
}
)
import readline from 'readline'
import { task, types } from 'hardhat/config'
import { ethers, Wallet } from 'ethers'
import { getContractsFromArtifacts } from '../src/deploy-utils'
task('update-dynamic-oracle-config', 'Updates the dynamic oracle config.')
.addParam(
'l2OutputOracleStartingTimestamp',
'Starting timestamp for the L2 output oracle.',
null,
types.int
)
.addParam('noSend', 'Do not send the transaction.', true, types.boolean)
.addOptionalParam(
'privateKey',
'Private key to send transaction',
process.env.PRIVATE_KEY,
types.string
)
.setAction(async (args, hre) => {
const { l2OutputOracleStartingTimestamp, noSend, privateKey } = args
const wallet = new Wallet(privateKey, hre.ethers.provider)
const [SystemDictator] = await getContractsFromArtifacts(hre, [
{
name: 'SystemDictatorProxy',
iface: 'SystemDictator',
signerOrProvider: wallet,
},
])
const currStep = await SystemDictator.currentStep()
if (currStep !== 5) {
throw new Error(`Current step is ${currStep}, expected 5`)
}
if (await SystemDictator.dynamicConfigSet()) {
throw new Error('Dynamic config already set')
}
const l2OutputOracleStartingBlockNumber =
hre.deployConfig.l2OutputOracleStartingBlockNumber
console.log(
`This task will set the L2 output oracle's starting timestamp and block number.`
)
console.log(
`It can only be run once. Please carefully check the values below:`
)
console.log(
`L2OO starting block number: ${l2OutputOracleStartingBlockNumber}`
)
console.log(
`L2OO starting block timestamp: ${l2OutputOracleStartingTimestamp}`
)
await prompt('Press enter to continue...')
if (noSend) {
const tx =
await SystemDictator.populateTransaction.updateL2OutputOracleDynamicConfig(
{
l2OutputOracleStartingBlockNumber,
l2OutputOracleStartingTimestamp,
}
)
console.log(`Sending is disabled. Transaction data:`)
// Need to delete tx.from for Ethers to properly serialize the tx
delete tx.from
console.log(ethers.utils.serializeTransaction(tx))
console.log(`Calldata (for multisigs):`)
console.log(tx.data)
} else {
console.log(`Sending transaction...`)
const tx = await SystemDictator.updateL2OutputOracleDynamicConfig({
l2OutputOracleStartingBlockNumber,
l2OutputOracleStartingTimestamp,
})
console.log(
`Transaction sent with hash ${tx.hash}. Waiting for receipt...`
)
const receipt = await tx.wait(1)
console.log(`Transaction included in block ${receipt.blockNumber}`)
}
})
const prompt = async (question: string) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
return new Promise<void>((resolve) => {
rl.question(question, () => {
rl.close()
resolve()
})
})
}
import { task, types } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { OpNodeProvider, sleep } from '@eth-optimism/core-utils'
import { predeploys } from '../src'
task('watch', 'Watch an Optimism System')
.addParam(
'l1ProviderUrl',
'L1 provider URL.',
'http://localhost:8545',
types.string
)
.addParam(
'l2ProviderUrl',
'L2 provider URL.',
'http://localhost:9545',
types.string
)
.addParam(
'opNodeProviderUrl',
'op-node provider URL',
'http://localhost:7545',
types.string
)
.setAction(async (args, hre) => {
const { utils } = hre.ethers
const l1Provider = new hre.ethers.providers.StaticJsonRpcProvider(
args.l1Provider
)
const l2Provider = new hre.ethers.providers.StaticJsonRpcProvider(
args.l2ProviderUrl
)
const contracts = {}
const deployments = await hre.deployments.all()
for (const [contract, deployment] of Object.entries(deployments)) {
contracts[contract] = deployment.address
}
console.log('Deployed Contracts')
console.table(contracts)
const opNodeProvider = new OpNodeProvider(args.opNodeProviderUrl)
const opNodeConfig = await opNodeProvider.rollupConfig()
console.log('op-node config')
console.table({
'layer-one-hash': opNodeConfig.genesis.l1.hash,
'layer-one-number': opNodeConfig.genesis.l1.number,
'layer-two-hash': opNodeConfig.genesis.l2.hash,
'layer-two-number': opNodeConfig.genesis.l2.number,
'layer-two-time': opNodeConfig.genesis.l2_time,
'block-time': opNodeConfig.block_time,
'max-sequencer-drift': opNodeConfig.max_sequencer_drift,
'seq-window-size': opNodeConfig.seq_window_size,
'channel-timeout': opNodeConfig.channel_timeout,
'l1-chain-id': opNodeConfig.l1_chain_id,
'l2-chain-id': opNodeConfig.l2_chain_id,
'p2p-sequencer-address': opNodeConfig.p2p_sequencer_address,
'fee-recipient-address': opNodeConfig.fee_recipient_address,
'batch-inbox-address': opNodeConfig.batch_inbox_address,
'batch-sender-address': opNodeConfig.batch_sender_address,
'deposit-contract-address': opNodeConfig.deposit_contract_address,
})
const Deployment__L2OutputOracle = await hre.deployments.get(
'L2OutputOracle'
)
const Deployment__L2OutputOracleProxy = await hre.deployments.get(
'L2OutputOracleProxy'
)
const L2OutputOracle = new hre.ethers.Contract(
Deployment__L2OutputOracleProxy.address,
Deployment__L2OutputOracle.abi,
l1Provider
)
const proposer = await L2OutputOracle.proposer()
console.log(`L2OutputOracle proposer ${proposer}`)
console.log()
setInterval(async () => {
const latestBlockNumber = await L2OutputOracle.latestBlockNumber()
console.log(
`L2OutputOracle latest block number: ${latestBlockNumber.toString()}`
)
console.log()
}, 10000)
l1Provider.on('block', async (num) => {
const block = await l1Provider.getBlockWithTransactions(num)
for (const txn of block.transactions) {
const to = utils.getAddress(txn.to || hre.ethers.constants.AddressZero)
const from = utils.getAddress(txn.from)
const isBatchSender =
utils.getAddress(txn.from) ===
utils.getAddress(opNodeConfig.batch_sender_address)
const isBatchInbox =
to === utils.getAddress(opNodeConfig.batch_inbox_address)
const isOutputOracle =
to === utils.getAddress(L2OutputOracle.address) &&
from === utils.getAddress(proposer)
if (isBatchSender && isBatchInbox) {
console.log('Batch submitted:')
console.log(` tx hash: ${txn.hash}`)
console.log(` tx data: ${txn.data}`)
console.log()
}
if (isOutputOracle) {
console.log('L2 Output Submitted:')
const data = L2OutputOracle.interface.parseTransaction(txn)
console.log(` tx hash: ${txn.hash}`)
console.log(` output root: ${data.args._outputRoot}`)
console.log(` l2 blocknum: ${data.args._l2BlockNumber}`)
console.log(` l1 blockhash: ${data.args._l1Blockhash}`)
console.log(` l1 blocknum: ${data.args._l1BlockNumber}`)
console.log()
}
}
})
const L1Block = await hre.ethers.getContractAt(
'L1Block',
predeploys.L1Block
)
l2Provider.on('block', async (num) => {
const block = await l2Provider.getBlockWithTransactions(num)
for (const txn of block.transactions) {
const to = utils.getAddress(txn.to || hre.ethers.constants.AddressZero)
if (to === utils.getAddress(predeploys.L1Block)) {
const data = L1Block.interface.parseTransaction(txn)
console.log('L1Block values updated')
console.log(` tx hash: ${txn.hash}`)
console.log(` number: ${data.args._number}`)
console.log(` timestamp: ${data.args._timestamp}`)
console.log(` basefee: ${data.args._basefee}`)
console.log(` hash: ${data.args._hash}`)
console.log(` sequenceNumber: ${data.args._sequenceNumber}`)
console.log()
}
}
})
setInterval(async () => {
await sleep(100000)
})
await sleep(100000)
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment