Commit 700dcbb0 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts-bedrock: genesis builder (#2781)

* contracts-bedrock: hardhat genesis-l1

* contracts-bedrock: hardhat genesis-l2

* core-utils: update types

* contracts-bedrock: hardhat rollup-config

* contracts-bedrock: update deploy scripts

* contracts-governance: more solc output

* contracts-bedrock: deploy config

* contracts-bedrock: general fixes

* ops-bedrock: use new script

* lint

* lint: fix
parent a828da9f
---
'@eth-optimism/contracts-bedrock': patch
---
Add genesis script
---
'@eth-optimism/core-utils': minor
---
Update geth's Genesis type to work with modern geth
...@@ -33,6 +33,7 @@ L1_URL="http://localhost:8545" ...@@ -33,6 +33,7 @@ L1_URL="http://localhost:8545"
L2_URL="http://localhost:9545" L2_URL="http://localhost:9545"
CONTRACTS_BEDROCK=./packages/contracts-bedrock CONTRACTS_BEDROCK=./packages/contracts-bedrock
NETWORK=devnetL1
# Helper method that waits for a given URL to be up. Can't use # Helper method that waits for a given URL to be up. Can't use
# cURL's built-in retry logic because connection reset errors # cURL's built-in retry logic because connection reset errors
...@@ -46,7 +47,7 @@ function wait_up { ...@@ -46,7 +47,7 @@ function wait_up {
sleep 0.25 sleep 0.25
((i=i+1)) ((i=i+1))
if [ "$i" -eq 120 ]; then if [ "$i" -eq 200 ]; then
echo " Timeout!" >&2 echo " Timeout!" >&2
exit 0 exit 0
fi fi
...@@ -54,15 +55,24 @@ function wait_up { ...@@ -54,15 +55,24 @@ function wait_up {
echo "Done!" echo "Done!"
} }
mkdir -p ./.devnet
if [ ! -f ./.devnet/rollup.json ]; then
GENESIS_TIMESTAMP=$(date +%s | xargs printf "0x%x")
else
GENESIS_TIMESTAMP=$(jq '.genesis.l2_time' < .devnet/rollup.json)
fi
# Regenerate the L1 genesis file if necessary. The existence of the genesis # Regenerate the L1 genesis file if necessary. The existence of the genesis
# file is used to determine if we need to recreate the devnet's state folder. # file is used to determine if we need to recreate the devnet's state folder.
if [ ! -f ./.devnet/genesis-l1.json ]; then if [ ! -f ./.devnet/genesis-l1.json ]; then
echo "Regenerating L1 genesis." echo "Regenerating L1 genesis."
mkdir -p ./.devnet (
GENESIS_TIMESTAMP=$(date +%s | xargs printf "0x%x") cd $CONTRACTS_BEDROCK
jq ". | .timestamp = \"$GENESIS_TIMESTAMP\" " < ./ops-bedrock/genesis-l1.json > ./.devnet/genesis-l1.json L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP npx hardhat genesis-l1 \
else --outfile genesis-l1.json
GENESIS_TIMESTAMP=$(jq -r '.timestamp' < ./.devnet/genesis-l1.json) mv genesis-l1.json ../../.devnet/genesis-l1.json
)
fi fi
# Bring up L1. # Bring up L1.
...@@ -75,43 +85,27 @@ fi ...@@ -75,43 +85,27 @@ fi
) )
# Deploy contracts using Hardhat. # Deploy contracts using Hardhat.
if [ ! -f $CONTRACTS_BEDROCK/deployments/devnetL1/OptimismPortal.json ]; then if [ ! -d $CONTRACTS_BEDROCK/deployments/$NETWORK ]; then
echo "Deploying contracts."
( (
echo "Deploying contracts."
cd $CONTRACTS_BEDROCK cd $CONTRACTS_BEDROCK
L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP yarn hardhat --network devnetL1 deploy L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP yarn hardhat --network $NETWORK deploy
) )
else else
echo "Contracts already deployed, skipping." echo "Contracts already deployed, skipping."
fi fi
function get_deployed_bytecode() { if [ ! -f ./.devnet/genesis-l2.json ]; then
echo $(jq -r .deployedBytecode $CONTRACTS_BEDROCK/artifacts/contracts/$1) (
} echo "Creating L2 genesis file."
cd $CONTRACTS_BEDROCK
# Pull out the necessary bytecode/addresses from the artifacts/deployments. L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP npx hardhat --network $NETWORK genesis-l2
L2_TO_L1_MESSAGE_PASSER_BYTECODE=$(get_deployed_bytecode L2/L2ToL1MessagePasser.sol/L2ToL1MessagePasser.json) mv genesis.json ../../.devnet/genesis-l2.json
L2_CROSS_DOMAIN_MESSENGER_BYTECODE=$(get_deployed_bytecode L2/L2CrossDomainMessenger.sol/L2CrossDomainMessenger.json) echo "Created L2 genesis."
OPTIMISM_MINTABLE_TOKEN_FACTORY_BYTECODE=$(get_deployed_bytecode universal/OptimismMintableTokenFactory.sol/OptimismMintableTokenFactory.json) )
L2_STANDARD_BRIDGE_BYTECODE=$(get_deployed_bytecode L2/L2StandardBridge.sol/L2StandardBridge.json) else
L1_BLOCK_INFO_BYTECODE=$(get_deployed_bytecode L2/L1Block.sol/L1Block.json) echo "L2 genesis already exists."
fi
DEPOSIT_CONTRACT_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/devnetL1/OptimismPortal.json)
L2OO_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/devnetL1/L2OutputOracle.json)
# Replace values in the L2 genesis file. It doesn't matter if this gets run every time,
# since the replaced values will be the same.
jq ". | .alloc.\"4200000000000000000000000000000000000015\".code = \"$L1_BLOCK_INFO_BYTECODE\"" < ./ops-bedrock/genesis-l2.json | \
jq ". | .alloc.\"4200000000000000000000000000000000000015\".balance = \"0x0\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000000\".code = \"$L2_TO_L1_MESSAGE_PASSER_BYTECODE\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000000\".balance = \"0x0\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000007\".code = \"$L2_CROSS_DOMAIN_MESSENGER_BYTECODE\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000007\".balance = \"0x0\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000012\".code = \"$OPTIMISM_MINTABLE_TOKEN_FACTORY_BYTECODE\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000012\".balance = \"0x0\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000010\".code = \"$L2_STANDARD_BRIDGE_BYTECODE\"" | \
jq ". | .alloc.\"4200000000000000000000000000000000000010\".balance = \"0x0\"" | \
jq ". | .timestamp = \"$GENESIS_TIMESTAMP\" " > ./.devnet/genesis-l2.json
# Bring up L2. # Bring up L2.
( (
...@@ -122,40 +116,19 @@ jq ". | .alloc.\"4200000000000000000000000000000000000015\".code = \"$L1_BLOCK_I ...@@ -122,40 +116,19 @@ jq ". | .alloc.\"4200000000000000000000000000000000000015\".code = \"$L1_BLOCK_I
) )
# Start putting together the rollup config. # Start putting together the rollup config.
echo "Building rollup config..." if [ ! -f ./.devnet/rollup.json ]; then
(
# Grab the L1 genesis. We can use cURL here to retry. echo "Building rollup config..."
L1_GENESIS=$(curl \ cd $CONTRACTS_BEDROCK
--silent \ L2OO_STARTING_BLOCK_TIMESTAMP=$GENESIS_TIMESTAMP npx hardhat rollup-config --network $NETWORK
--fail \ mv rollup.json ../../.devnet/rollup.json
--retry 10 \ )
--retry-delay 2 \ else
--retry-connrefused \ echo "Rollup config already exists"
-X POST \ fi
-H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' \ L2OO_ADDRESS=$(jq -r .address < $CONTRACTS_BEDROCK/deployments/$NETWORK/L2OutputOracleProxy.json)
$L1_URL) SEQUENCER_GENESIS_HASH="$(jq -r '.l2.hash' < .devnet/rollup.json)"
# Grab the L2 genesis. We can use cURL here to retry.
L2_GENESIS=$(curl \
--silent \
--fail \
--retry 10 \
--retry-delay 2 \
--retry-connrefused \
-X POST \
-H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0", false],"id":1}' \
$L2_URL)
# Generate the rollup config.
jq ". | .genesis.l1.hash = \"$(echo $L1_GENESIS | jq -r '.result.hash')\"" < ./ops-bedrock/rollup.json | \
jq ". | .genesis.l2.hash = \"$(echo $L2_GENESIS | jq -r '.result.hash')\"" | \
jq ". | .genesis.l2_time = $(echo $L2_GENESIS | jq -r '.result.timestamp' | xargs printf "%d")" | \
jq ". | .deposit_contract_address = \"$DEPOSIT_CONTRACT_ADDRESS\"" > ./.devnet/rollup.json
SEQUENCER_GENESIS_HASH="$(echo $L2_GENESIS | jq -r '.result.hash')"
SEQUENCER_BATCH_INBOX_ADDRESS="$(cat ./ops-bedrock/rollup.json | jq -r '.batch_inbox_address')" SEQUENCER_BATCH_INBOX_ADDRESS="$(cat ./ops-bedrock/rollup.json | jq -r '.batch_inbox_address')"
# Bring up everything else. # Bring up everything else.
......
This diff is collapsed.
This diff is collapsed.
import { ethers } from 'ethers' import { ethers } from 'ethers'
const { env } = process
const startingTimestamp =
typeof env.L2OO_STARTING_BLOCK_TIMESTAMP === 'string'
? ethers.BigNumber.from(env.L2OO_STARTING_BLOCK_TIMESTAMP).toNumber()
: Date.now() / 1000
const config = { const config = {
submissionInterval: 6, submissionInterval: 6,
genesisOutput: ethers.constants.HashZero, genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0, historicalBlocks: 0,
startingBlockNumber: 0, startingBlockNumber: 0,
startingTimestamp:
parseInt(process.env.L2OO_STARTING_BLOCK_TIMESTAMP, 10) || Date.now(),
l2BlockTime: 2, l2BlockTime: 2,
startingTimestamp,
sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
l2CrossDomainMessengerOwner: ethers.constants.AddressZero,
gasPriceOracleOwner: ethers.constants.AddressZero,
gasPriceOracleOverhead: 2100,
gasPriceOracleScalar: 1000000,
gasPriceOracleDecimals: 6,
l1BlockInitialNumber: 0,
l1BlockInitialTimestamp: 0,
l1BlockInitialBasefee: 10,
l1BlockInitialHash: ethers.constants.HashZero,
l1BlockInitialSequenceNumber: 0,
proxyAdmin: '0x829BD824B016326A401d083B33D092293333A830',
genesisBlockExtradata: ethers.utils.hexConcat([
ethers.constants.HashZero,
'0xca062b0fd91172d89bcd4bb084ac4e21972cc467',
ethers.utils.hexZeroPad('0x', 65),
]),
genesisBlockGasLimit: ethers.BigNumber.from(15000000).toHexString(),
genesisBlockChainid: 901,
fundDevAccounts: true,
optimsismBaseFeeRecipient: '0xBcd4042DE499D14e55001CcbB24a551F3b954096',
optimismL1FeeRecipient: '0x71bE63f3384f5fb98995898A86B02Fb2426c5788',
deploymentWaitConfirmations: 1,
maxSequencerDrift: 10,
sequencerWindowSize: 2,
ownerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', ownerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
} }
......
...@@ -5,7 +5,7 @@ const config = { ...@@ -5,7 +5,7 @@ const config = {
l2BlockTime: 2, l2BlockTime: 2,
genesisOutput: ethers.constants.HashZero, genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0, historicalBlocks: 0,
startingBlockTimestamp: 1652907966, startingTimestamp: 1652907966,
sequencerAddress: '0x7431310e026B69BFC676C0013E12A1A11411EEc9', sequencerAddress: '0x7431310e026B69BFC676C0013E12A1A11411EEc9',
} }
......
import { ethers } from 'ethers' import { ethers } from 'ethers'
const { env } = process
const startingTimestamp =
typeof env.L2OO_STARTING_BLOCK_TIMESTAMP === 'string'
? ethers.BigNumber.from(env.L2OO_STARTING_BLOCK_TIMESTAMP).toNumber()
: Date.now() / 1000
const config = { const config = {
submissionInterval: 6, submissionInterval: 6,
genesisOutput: ethers.constants.HashZero, genesisOutput: ethers.constants.HashZero,
historicalBlocks: 0, historicalBlocks: 0,
startingBlockNumber: 0, startingBlockNumber: 0,
startingTimestamp:
parseInt(process.env.L2OO_STARTING_BLOCK_TIMESTAMP, 10) || Date.now(),
l2BlockTime: 2, l2BlockTime: 2,
startingTimestamp,
sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', sequencerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
maxSequencerDrift: 10,
sequencerWindowSize: 2,
ownerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', ownerAddress: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
} }
......
/* Imports: Internal */ /* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import { BigNumber } from 'ethers'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
if ( if (
typeof hre.deployConfig.startingTimestamp !== 'number' || typeof deployConfig.startingTimestamp !== 'number' ||
isNaN(hre.deployConfig.startingTimestamp) isNaN(deployConfig.startingTimestamp)
) { ) {
throw new Error( throw new Error(
'Cannot deploy L2OutputOracle without specifying a valid startingTimestamp.' 'Cannot deploy L2OutputOracle without specifying a valid startingTimestamp.'
) )
} }
await deploy('L2OutputOracleProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
await deploy('L2OutputOracle', { await deploy('L2OutputOracle', {
from: deployer, from: deployer,
args: [ args: [
hre.deployConfig.submissionInterval, deployConfig.submissionInterval,
hre.deployConfig.genesisOutput, deployConfig.genesisOutput,
hre.deployConfig.historicalBlocks, deployConfig.historicalBlocks,
hre.deployConfig.startingBlockNumber, deployConfig.startingBlockNumber,
hre.deployConfig.startingTimestamp, deployConfig.startingTimestamp,
hre.deployConfig.l2BlockTime, deployConfig.l2BlockTime,
hre.deployConfig.sequencerAddress, deployConfig.sequencerAddress,
hre.deployConfig.ownerAddress, deployConfig.ownerAddress,
], ],
log: true, log: true,
waitConfirmations: 1, waitConfirmations: deployConfig.deploymentWaitConfirmations,
}) })
const oracle = await hre.deployments.get('L2OutputOracle')
const proxy = await hre.deployments.get('L2OutputOracleProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const tx = await Proxy.upgradeTo(oracle.address)
await tx.wait()
const L2OutputOracle = await hre.ethers.getContractAt(
'L2OutputOracle',
proxy.address
)
const submissionInterval = await L2OutputOracle.SUBMISSION_INTERVAL()
if (!submissionInterval.eq(BigNumber.from(deployConfig.submissionInterval))) {
throw new Error('submission internal misconfigured')
}
const historicalBlocks = await L2OutputOracle.HISTORICAL_TOTAL_BLOCKS()
if (!historicalBlocks.eq(BigNumber.from(deployConfig.historicalBlocks))) {
throw new Error('historal total blocks misconfigured')
}
const startingBlockNumber = await L2OutputOracle.STARTING_BLOCK_NUMBER()
if (
!startingBlockNumber.eq(BigNumber.from(deployConfig.startingBlockNumber))
) {
throw new Error('starting block number misconfigured')
}
const startingTimestamp = await L2OutputOracle.STARTING_TIMESTAMP()
if (!startingTimestamp.eq(BigNumber.from(deployConfig.startingTimestamp))) {
throw new Error('starting timestamp misconfigured')
}
const l2BlockTime = await L2OutputOracle.L2_BLOCK_TIME()
if (!l2BlockTime.eq(BigNumber.from(deployConfig.l2BlockTime))) {
throw new Error('L2 block time misconfigured')
}
} }
deployFn.tags = ['L2OutputOracle'] deployFn.tags = ['L2OutputOracle']
......
/* Imports: Internal */ /* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy, get } = hre.deployments const { deploy, get } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('OptimismPortalProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
const oracle = await get('L2OutputOracle') const oracle = await get('L2OutputOracle')
await deploy('OptimismPortal', { await deploy('OptimismPortal', {
from: deployer, from: deployer,
args: [oracle.address, 2], args: [oracle.address, 2],
log: true, log: true,
waitConfirmations: 1, waitConfirmations: deployConfig.deploymentWaitConfirmations,
}) })
const proxy = await hre.deployments.get('OptimismPortalProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const portal = await hre.deployments.get('OptimismPortal')
const tx = await Proxy.upgradeTo(portal.address)
await tx.wait()
const OptimismPortal = await hre.ethers.getContractAt(
'OptimismPortal',
proxy.address
)
const l2Oracle = await OptimismPortal.L2_ORACLE()
if (l2Oracle !== oracle.address) {
throw new Error('L2 Oracle mismatch')
}
} }
deployFn.tags = ['OptimismPortal'] deployFn.tags = ['OptimismPortal']
......
/* Imports: Internal */ /* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import { Contract } from 'ethers'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('L1CrossDomainMessengerProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
await deploy('L1CrossDomainMessenger', { await deploy('L1CrossDomainMessenger', {
from: deployer, from: deployer,
args: [], args: [],
log: true, log: true,
waitConfirmations: 1, waitConfirmations: deployConfig.deploymentWaitConfirmations,
}) })
const provider = hre.ethers.provider.getSigner(deployer) const proxy = await hre.deployments.get('L1CrossDomainMessengerProxy')
const portal = await hre.deployments.get('OptimismPortal') const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const messenger = await hre.deployments.get('L1CrossDomainMessenger') const messenger = await hre.deployments.get('L1CrossDomainMessenger')
const portal = await hre.deployments.get('OptimismPortal')
const L1CrossDomainMessenger = await hre.ethers.getContractAt(
'L1CrossDomainMessenger',
proxy.address
)
const L1CrossDomainMessenger = new Contract( const upgradeTx = await Proxy.upgradeToAndCall(
messenger.address, messenger.address,
messenger.abi, L1CrossDomainMessenger.interface.encodeFunctionData('initialize(address)', [
provider portal.address,
])
) )
await upgradeTx.wait()
const tx = await L1CrossDomainMessenger.initialize(portal.address) const portalAddress = await L1CrossDomainMessenger.portal()
const receipt = await tx.wait() if (portalAddress !== portal.address) {
console.log(`${receipt.transactionHash}: initialize(${portal.address})`) throw new Error('portal misconfigured')
}
} }
deployFn.tags = ['L1CrossDomainMessenger'] deployFn.tags = ['L1CrossDomainMessenger']
......
/* Imports: Internal */ /* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import { Contract } from 'ethers'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('L1StandardBridgeProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
await deploy('L1StandardBridge', { await deploy('L1StandardBridge', {
from: deployer, from: deployer,
args: [], args: [],
log: true, log: true,
waitConfirmations: 1, waitConfirmations: deployConfig.deploymentWaitConfirmations,
}) })
const provider = hre.ethers.provider.getSigner(deployer) const proxy = await hre.deployments.get('L1StandardBridgeProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const messenger = await hre.deployments.get('L1CrossDomainMessenger')
const bridge = await hre.deployments.get('L1StandardBridge') const bridge = await hre.deployments.get('L1StandardBridge')
const messenger = await hre.deployments.get('L1CrossDomainMessengerProxy')
const L1StandardBridge = new Contract(bridge.address, bridge.abi, provider)
const L1StandardBridge = await hre.ethers.getContractAt(
const tx = await L1StandardBridge.initialize(messenger.address) 'L1StandardBridge',
const receipt = await tx.wait() proxy.address
console.log(`${receipt.transactionHash}: initialize(${messenger.address})`) )
const upgradeTx = await Proxy.upgradeToAndCall(
bridge.address,
L1StandardBridge.interface.encodeFunctionData('initialize(address)', [
messenger.address,
])
)
await upgradeTx.wait()
if (messenger.address !== (await L1StandardBridge.messenger())) {
throw new Error('misconfigured messenger')
}
} }
deployFn.tags = ['L1StandardBridge'] deployFn.tags = ['L1StandardBridge']
......
/* Imports: Internal */ /* Imports: Internal */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
import { Contract } from 'ethers'
import 'hardhat-deploy' import 'hardhat-deploy'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const { deployConfig } = hre
await deploy('OptimismMintableTokenFactoryProxy', {
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
waitConfirmations: deployConfig.deploymentWaitConfirmations,
})
await deploy('OptimismMintableTokenFactory', { await deploy('OptimismMintableTokenFactory', {
from: deployer, from: deployer,
args: [], args: [],
log: true, log: true,
waitConfirmations: 1, waitConfirmations: deployConfig.deploymentWaitConfirmations,
}) })
const provider = hre.ethers.provider.getSigner(deployer)
const factory = await hre.deployments.get('OptimismMintableTokenFactory') const factory = await hre.deployments.get('OptimismMintableTokenFactory')
const bridge = await hre.deployments.get('L1StandardBridge') const bridge = await hre.deployments.get('L1StandardBridgeProxy')
const proxy = await hre.deployments.get('OptimismMintableTokenFactoryProxy')
const Proxy = await hre.ethers.getContractAt('Proxy', proxy.address)
const OptimismMintableTokenFactory = await hre.ethers.getContractAt(
'OptimismMintableTokenFactory',
proxy.address
)
const OptimismMintableTokenFactory = new Contract( const upgradeTx = await Proxy.upgradeToAndCall(
factory.address, factory.address,
factory.abi, OptimismMintableTokenFactory.interface.encodeFunctionData(
provider 'initialize(address)',
[bridge.address]
)
) )
await upgradeTx.wait()
const tx = await OptimismMintableTokenFactory.initialize(bridge.address) if (bridge.address !== (await OptimismMintableTokenFactory.bridge())) {
const receipt = await tx.wait() throw new Error('bridge misconfigured')
console.log(`${receipt.transactionHash}: initialize(${bridge.address})`) }
} }
deployFn.tags = ['OptimismMintableTokenFactory'] deployFn.tags = ['OptimismMintableTokenFactory']
......
...@@ -13,4 +13,6 @@ remappings = [ ...@@ -13,4 +13,6 @@ remappings = [
'ds-test/=node_modules/ds-test/src' 'ds-test/=node_modules/ds-test/src'
] ]
extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout'] extra_output = ['devdoc', 'userdoc', 'metadata', 'storageLayout']
bytecode_hash = "none" bytecode_hash = 'none'
# build_info = true
...@@ -3,7 +3,7 @@ import { HardhatUserConfig, task, subtask } from 'hardhat/config' ...@@ -3,7 +3,7 @@ import { HardhatUserConfig, task, subtask } from 'hardhat/config'
import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from 'hardhat/builtin-tasks/task-names' import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from 'hardhat/builtin-tasks/task-names'
// Hardhat plugins // Hardhat plugins
import '@nomiclabs/hardhat-waffle' import '@nomiclabs/hardhat-ethers'
import '@typechain/hardhat' import '@typechain/hardhat'
import 'solidity-coverage' import 'solidity-coverage'
import 'hardhat-deploy' import 'hardhat-deploy'
...@@ -11,7 +11,10 @@ import '@foundry-rs/hardhat-forge' ...@@ -11,7 +11,10 @@ import '@foundry-rs/hardhat-forge'
import '@eth-optimism/hardhat-deploy-config' import '@eth-optimism/hardhat-deploy-config'
// Hardhat tasks // Hardhat tasks
import './tasks/genesis-l1'
import './tasks/genesis-l2'
import './tasks/deposits' import './tasks/deposits'
import './tasks/rollup-config'
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction( subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(
async (_, __, runSuper) => { async (_, __, runSuper) => {
...@@ -84,6 +87,19 @@ const config: HardhatUserConfig = { ...@@ -84,6 +87,19 @@ const config: HardhatUserConfig = {
type: 'address', type: 'address',
}, },
}, },
external: {
contracts: [
{
artifacts: '../contracts/artifacts',
},
{
artifacts: '../contracts-governance/artifacts',
},
],
deployments: {
goerli: ['../contracts/deployments/goerli'],
},
},
solidity: { solidity: {
compilers: [ compilers: [
{ {
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eth-optimism/hardhat-deploy-config": "^0.2.0", "@eth-optimism/hardhat-deploy-config": "^0.2.0",
"@defi-wonderland/smock": "^2.0.2",
"@foundry-rs/hardhat-forge": "^0.1.7", "@foundry-rs/hardhat-forge": "^0.1.7",
"@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-waffle": "^2.0.0", "@nomiclabs/hardhat-waffle": "^2.0.0",
......
/** /**
* Predeploys are Solidity contracts that are injected into the initial L2 state and provide * Predeploys are Solidity contracts that are injected into the initial L2 state and provide
* various useful functions. * various useful functions.
* Notes:
* 0x42...04 was the address of the OVM_ProxySequencerEntrypoint. This contract is no longer in
* use and has therefore been removed. We may place a new predeployed contract at this address
* in the future. See https://github.com/ethereum-optimism/optimism/pull/549 for more info.
*/ */
export const bedrockPredeploys = { export const predeploys = {
L1_BLOCK_ATTRIBUTES: '0x4200000000000000000000000000000000000015', L2ToL1MessagePasser: '0x4200000000000000000000000000000000000000',
WITHDRAWER: '0x4200000000000000000000000000000000000016', DeployerWhitelist: '0x4200000000000000000000000000000000000002',
L2CrossDomainMessenger: '0x4200000000000000000000000000000000000007',
GasPriceOracle: '0x420000000000000000000000000000000000000F',
L2StandardBridge: '0x4200000000000000000000000000000000000010',
SequencerFeeVault: '0x4200000000000000000000000000000000000011',
OptimismMintableTokenFactory: '0x4200000000000000000000000000000000000012',
L1BlockNumber: '0x4200000000000000000000000000000000000013',
L1Block: '0x4200000000000000000000000000000000000015',
OVM_ETH: '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000',
WETH9: '0x4200000000000000000000000000000000000006',
GovernanceToken: '0x4200000000000000000000000000000000000042',
}
export const futurePredeploys = {
System1: '0x4200000000000000000000000000000000000014',
} }
...@@ -2,7 +2,7 @@ import { ethers } from 'ethers' ...@@ -2,7 +2,7 @@ import { ethers } from 'ethers'
import { toHexString } from '@eth-optimism/core-utils' import { toHexString } from '@eth-optimism/core-utils'
import { TrieTestGenerator } from './trie-test-generator' import { TrieTestGenerator } from './trie-test-generator'
import { bedrockPredeploys } from './constants' import { predeploys } from './constants'
interface WithdrawalArgs { interface WithdrawalArgs {
nonce: number nonce: number
...@@ -63,7 +63,7 @@ export const generateMockWithdrawalProof = async ( ...@@ -63,7 +63,7 @@ export const generateMockWithdrawalProof = async (
const generator = await TrieTestGenerator.fromAccounts({ const generator = await TrieTestGenerator.fromAccounts({
accounts: [ accounts: [
{ {
address: bedrockPredeploys.WITHDRAWER, address: predeploys.L2ToL1MessagePasser,
nonce: 0, nonce: 0,
balance: 0, balance: 0,
codeHash: ethers.utils.keccak256('0x1234'), codeHash: ethers.utils.keccak256('0x1234'),
......
import fs from 'fs'
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import { Genesis, State } from '@eth-optimism/core-utils'
task('genesis-l1', 'create a genesis config')
.addOptionalParam(
'outfile',
'The file to write the output JSON to',
'genesis.json'
)
.setAction(async (args, hre) => {
// TODO: type needs to be updated to work with modern geth
const alloc: State | any = {}
// Give each predeploy a single wei
for (let i = 0; i <= 0xff; i++) {
const buf = Buffer.alloc(2)
buf.writeUInt16BE(i, 0)
const addr = ethers.utils.hexConcat([
'0x000000000000000000000000000000000000',
ethers.utils.hexZeroPad(buf, 2),
])
alloc[addr] = {
balance: '0x1',
}
}
// Prefund dev accounts
const accounts = [
'0x14dC79964da2C08b23698B3D3cc7Ca32193d9955',
'0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',
'0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec',
'0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f',
'0x2546BcD3c84621e976D8185a91A922aE77ECEc30',
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
'0x71bE63f3384f5fb98995898A86B02Fb2426c5788',
'0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199',
'0x90F79bf6EB2c4f870365E785982E1f101E93b906',
'0x976EA74026E726554dB657fA54763abd0C3a0aa9',
'0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
'0xBcd4042DE499D14e55001CcbB24a551F3b954096',
'0xFABB0ac9d68B0B445fB7357272Ff202C5651694a',
'0xa0Ee7A142d267C1f36714E4a8F75612F20a79720',
'0xbDA5747bFD65F08deb54cb465eB87D40e51B197E',
'0xcd3B766CCDd6AE721141F452C550Ca635964ce71',
'0xdD2FD4581271e230360230F9337D5c0430Bf44C0',
'0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097',
'0xde3829a23df1479438622a08a116e8eb3f620bb5',
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
]
const signers = await hre.ethers.getSigners()
for (const signer of signers) {
accounts.push(signer.address)
}
for (const account of accounts) {
alloc[ethers.utils.getAddress(account)] = {
balance:
'0x200000000000000000000000000000000000000000000000000000000000000',
}
}
const timestamp = hre.deployConfig.startingTimestamp
if (timestamp === undefined) {
throw new Error('Must configure starting block timestamp')
}
const genesis: Genesis = {
config: {
chainId: 900,
homesteadBlock: 0,
eip150Block: 0,
eip150Hash:
'0x0000000000000000000000000000000000000000000000000000000000000000',
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
constantinopleBlock: 0,
petersburgBlock: 0,
istanbulBlock: 0,
muirGlacierBlock: 0,
berlinBlock: 0,
londonBlock: 0,
clique: {
period: 15,
epoch: 30000,
},
},
nonce: '0x0',
timestamp: ethers.BigNumber.from(timestamp).toHexString(),
extraData:
'0x0000000000000000000000000000000000000000000000000000000000000000ca062b0fd91172d89bcd4bb084ac4e21972cc4670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
gasLimit: ethers.BigNumber.from(15_000_000).toHexString(),
difficulty: '0x1',
mixHash:
'0x0000000000000000000000000000000000000000000000000000000000000000',
coinbase: '0x0000000000000000000000000000000000000000',
alloc,
}
fs.writeFileSync(args.outfile, JSON.stringify(genesis, null, 2))
})
import fs from 'fs'
import assert from 'assert'
import { OptimismGenesis, State } from '@eth-optimism/core-utils'
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { predeploys } from '../src'
const prefix = '0x420000000000000000000000000000000000'
const implementationSlot =
'0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'
const adminSlot =
'0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'
const toCodeAddr = (addr: string) => {
const address = ethers.utils.hexConcat([
'0xc0d3c0d3c03dc03dc03dc03dc03dc03dc03d',
'0x' + addr.slice(prefix.length),
])
return ethers.utils.getAddress(address)
}
const assertEvenLength = (str: string) => {
assert(str.length % 2 === 0, str)
}
// TODO: this can be replaced with the smock version after
// a new release of foundry-rs/hardhat
const getStorageLayout = async (
hre: HardhatRuntimeEnvironment,
name: string
) => {
const buildInfo = await hre.artifacts.getBuildInfo(name)
const key = Object.keys(buildInfo.output.contracts)[0]
return (buildInfo.output.contracts[key][name] as any).storageLayout
}
task('genesis-l2', 'create a genesis config')
.addOptionalParam(
'outfile',
'The file to write the output JSON to',
'genesis.json'
)
.setAction(async (args, hre) => {
const {
computeStorageSlots,
// eslint-disable-next-line @typescript-eslint/no-var-requires
} = require('@defi-wonderland/smock/dist/src/utils')
const { deployConfig } = hre
// Use the addresses of the proxies here instead of the implementations
// Be backwards compatible
let ProxyL1CrossDomainMessenger = await hre.deployments.getOrNull(
'Proxy__OVM_L1CrossDomainMessenger'
)
if (ProxyL1CrossDomainMessenger === undefined) {
ProxyL1CrossDomainMessenger = await hre.deployments.get(
'L1CrossDomainMessengerProxy'
)
}
// Be backwards compatible
let ProxyL1StandardBridge = await hre.deployments.getOrNull(
'Proxy__OVM_L1StandardBridge'
)
if (ProxyL1StandardBridge === undefined) {
ProxyL1StandardBridge = await hre.deployments.get('L1StandardBridgeProxy')
}
const variables = {
L2ToL1MessagePasser: {
nonce: 0,
},
L2CrossDomainMessenger: {
_initialized: 1,
_owner: deployConfig.l2CrossDomainMessengerOwner,
xDomainMsgSender: '0x000000000000000000000000000000000000dEaD',
msgNonce: 0,
otherMessenger: ProxyL1CrossDomainMessenger.address,
// TODO: handle blockedSystemAddresses mapping
// blockedSystemAddresses: [{key: '', value: ''}],
},
GasPriceOracle: {
_owner: deployConfig.gasPriceOracleOwner,
overhead: deployConfig.gasPriceOracleOverhead,
scalar: deployConfig.gasPriceOracleScalar,
decimals: deployConfig.gasPriceOracleDecimals,
},
L2StandardBridge: {
messenger: predeploys.L2CrossDomainMessenger,
otherBridge: ProxyL1StandardBridge.address,
},
SequencerFeeVault: {
l1FeeWallet: ethers.constants.AddressZero,
},
OptimismMintableTokenFactory: {
bridge: ethers.constants.AddressZero,
},
L1Block: {
number: deployConfig.l1BlockInitialNumber,
timestamp: deployConfig.l1BlockInitialTimestamp,
basefee: deployConfig.l1BlockInitialBasefee,
hash: deployConfig.l1BlockInitialHash,
sequenceNumber: deployConfig.l1BlockInitialSequenceNumber,
},
OVM_ETH: {
bridge: predeploys.L2StandardBridge,
remoteToken: ethers.constants.AddressZero,
_name: 'Ether',
_symbol: 'ETH',
},
WETH9: {
name: 'Wrapped Ether',
symbol: 'WETH',
decimals: 18,
},
GovernanceToken: {
name: 'Optimism',
symbol: 'OP',
_owner: deployConfig.proxyAdmin,
},
}
assertEvenLength(implementationSlot)
assertEvenLength(adminSlot)
assertEvenLength(deployConfig.proxyAdmin)
const predeployAddrs = new Set()
for (const addr of Object.values(predeploys)) {
predeployAddrs.add(ethers.utils.getAddress(addr))
}
// TODO: geth likes strings for nonce and balance now
const alloc: State = {}
// Set a proxy at each predeploy address
const proxy = await hre.artifacts.readArtifact('Proxy')
for (let i = 0; i <= 0xffff; i++) {
const num = ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
const addr = ethers.utils.getAddress(
ethers.utils.hexConcat([prefix, num])
)
// There is no proxy at OVM_ETH or the GovernanceToken
if (
addr === ethers.utils.getAddress(predeploys.OVM_ETH) ||
addr === ethers.utils.getAddress(predeploys.GovernanceToken)
) {
continue
}
alloc[addr] = {
nonce: '0x0',
balance: '0x0',
code: proxy.deployedBytecode,
storage: {
[adminSlot]: deployConfig.proxyAdmin,
},
}
if (predeployAddrs.has(ethers.utils.getAddress(addr))) {
alloc[addr].storage[implementationSlot] = toCodeAddr(addr)
}
}
// Set the GovernanceToken in the state
// Cannot easily set storage due to no easy access to compiler
// output
const governanceToken = await hre.deployments.getArtifact('GovernanceToken')
alloc[predeploys.GovernanceToken] = {
nonce: '0x0',
balance: '0x0',
code: governanceToken.deployedBytecode,
}
// Give each predeploy a single wei
for (let i = 0; i <= 0xff; i++) {
const buf = Buffer.alloc(2)
buf.writeUInt16BE(i, 0)
const addr = ethers.utils.hexConcat([
'0x000000000000000000000000000000000000',
ethers.utils.hexZeroPad(buf, 2),
])
alloc[addr] = {
balance: '0x1',
}
}
if (deployConfig.fundDevAccounts) {
const accounts = [
'0xde3829a23df1479438622a08a116e8eb3f620bb5',
'0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
]
const signers = await hre.ethers.getSigners()
for (const signer of signers) {
accounts.push(signer.address)
}
for (const account of accounts) {
alloc[account] = {
balance:
'0x200000000000000000000000000000000000000000000000000000000000000',
}
}
}
// Set the predeploys in the state
for (const [name, addr] of Object.entries(predeploys)) {
if (name === 'GovernanceToken') {
continue
}
const artifact = await hre.artifacts.readArtifact(name)
assertEvenLength(artifact.deployedBytecode)
const allocAddr = name === 'OVM_ETH' ? addr : toCodeAddr(addr)
assertEvenLength(allocAddr)
alloc[allocAddr] = {
nonce: '0x00',
balance: '0x00',
code: artifact.deployedBytecode,
storage: {},
}
const storageLayout = await getStorageLayout(hre, name)
const slots = computeStorageSlots(storageLayout, variables[name])
for (const slot of slots) {
alloc[allocAddr].storage[slot.key] = slot.val
}
}
const genesis: OptimismGenesis = {
config: {
chainId: deployConfig.genesisBlockChainid,
homesteadBlock: 0,
eip150Block: 0,
eip155Block: 0,
eip158Block: 0,
byzantiumBlock: 0,
constantinopleBlock: 0,
petersburgBlock: 0,
istanbulBlock: 0,
muirGlacierBlock: 0,
berlinBlock: 0,
londonBlock: 0,
mergeForkBlock: 0,
terminalTotalDifficulty: 0,
clique: {
period: 0,
epoch: 30000,
},
},
nonce: '0x1234',
difficulty: '0x1',
timestamp: ethers.BigNumber.from(
deployConfig.startingTimestamp
).toHexString(),
gasLimit: deployConfig.genesisBlockGasLimit,
extraData: deployConfig.genesisBlockExtradata,
optimism: {
enabled: true,
baseFeeRecipient: deployConfig.optimsismBaseFeeRecipient,
l1FeeRecipient: deployConfig.optimismL1FeeRecipient,
},
alloc,
}
fs.writeFileSync(args.outfile, JSON.stringify(genesis, null, 2))
})
import fs from 'fs'
import { task } from 'hardhat/config'
import { OpNodeConfig, getChainId } from '@eth-optimism/core-utils'
import { ethers } from 'ethers'
task('rollup-config', 'create a genesis config')
.addOptionalParam(
'outfile',
'The file to write the output JSON to',
'rollup.json'
)
.addOptionalParam('l1RpcUrl', 'The L1 RPC URL', 'http://127.0.0.1:8545')
.addOptionalParam('l2RpcUrl', 'The L2 RPC URL', 'http://127.0.0.1:9545')
.setAction(async (args, hre) => {
const { deployConfig } = hre
const l1 = new ethers.providers.StaticJsonRpcProvider(args.l1RpcUrl)
const l2 = new ethers.providers.StaticJsonRpcProvider(args.l2RpcUrl)
const l1Genesis = await l1.getBlock('earliest')
const l2Genesis = await l2.getBlock('earliest')
const portal = await hre.deployments.get('OptimismPortalProxy')
const config: OpNodeConfig = {
genesis: {
l1: {
hash: l1Genesis.hash,
number: 0,
},
l2: {
hash: l2Genesis.hash,
number: 0,
},
l2_time: deployConfig.startingTimestamp,
},
block_time: deployConfig.l2BlockTime,
max_sequencer_drift: deployConfig.maxSequencerDrift,
seq_window_size: deployConfig.sequencerWindowSize,
l1_chain_id: await getChainId(l1),
l2_chain_id: await getChainId(l2),
p2p_sequencer_address: '0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc',
fee_recipient_address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
batch_inbox_address: '0xff00000000000000000000000000000000000002',
batch_sender_address: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
deposit_contract_address: portal.address,
}
fs.writeFileSync(args.outfile, JSON.stringify(config, null, 2))
})
...@@ -77,7 +77,16 @@ const privKey = process.env.PRIVATE_KEY || '0x' + '11'.repeat(32) ...@@ -77,7 +77,16 @@ const privKey = process.env.PRIVATE_KEY || '0x' + '11'.repeat(32)
* @type import("hardhat/config").HardhatUserConfig * @type import("hardhat/config").HardhatUserConfig
*/ */
module.exports = { module.exports = {
solidity: '0.8.12', solidity: {
version: '0.8.12',
settings: {
outputSelection: {
'*': {
'*': ['metadata', 'storageLayout'],
},
},
},
},
networks: { networks: {
optimism: { optimism: {
chainId: 17, chainId: 17,
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
*/ */
export interface State { export interface State {
[address: string]: { [address: string]: {
nonce: number nonce?: string
balance: string balance?: string
codeHash?: string codeHash?: string
root?: string root?: string
code?: string code?: string
...@@ -24,6 +24,7 @@ export interface ChainConfig { ...@@ -24,6 +24,7 @@ export interface ChainConfig {
chainId: number chainId: number
homesteadBlock: number homesteadBlock: number
eip150Block: number eip150Block: number
eip150Hash?: string
eip155Block: number eip155Block: number
eip158Block: number eip158Block: number
byzantiumBlock: number byzantiumBlock: number
...@@ -34,6 +35,7 @@ export interface ChainConfig { ...@@ -34,6 +35,7 @@ export interface ChainConfig {
berlinBlock: number berlinBlock: number
londonBlock?: number londonBlock?: number
arrowGlacierBlock?: number arrowGlacierBlock?: number
grayGlacierBlock?: number
mergeForkBlock?: number mergeForkBlock?: number
terminalTotalDifficulty?: number terminalTotalDifficulty?: number
clique?: { clique?: {
...@@ -48,12 +50,31 @@ export interface ChainConfig { ...@@ -48,12 +50,31 @@ export interface ChainConfig {
*/ */
export interface Genesis { export interface Genesis {
config: ChainConfig config: ChainConfig
nonce?: number nonce?: string
timestamp?: number timestamp?: string
difficulty: string difficulty: string
mixHash?: string mixHash?: string
coinbase?: string coinbase?: string
number?: string
gasLimit: string gasLimit: string
gasUsed?: string
parentHash?: string
extraData: string extraData: string
alloc: State alloc: State
} }
/**
* Represents the chain config for an Optimism chain
*/
export interface OptimismChainConfig {
enabled: boolean
baseFeeRecipient: string
l1FeeRecipient: string
}
/**
* Represents the Genesis file format for an Optimism chain
*/
export interface OptimismGenesis extends Genesis {
optimism: OptimismChainConfig
}
...@@ -6,3 +6,4 @@ export * from './alias' ...@@ -6,3 +6,4 @@ export * from './alias'
export * from './batch-encoding' export * from './batch-encoding'
export * from './fees' export * from './fees'
export * from './rollup-types' export * from './rollup-types'
export * from './op-node'
export interface OpNodeConfig {
genesis: {
l1: {
hash: string
number: number
}
l2: {
hash: string
number: number
}
l2_time: number
}
block_time: number
max_sequencer_drift: number
seq_window_size: number
l1_chain_id: number
l2_chain_id: number
p2p_sequencer_address: string
fee_recipient_address: string
batch_inbox_address: string
batch_sender_address: string
deposit_contract_address: string
}
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